@adapt-toolkit/a2adapt 0.11.3 → 0.11.5

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.11.3",
6
+ "version": "0.11.5",
7
7
  "author": {
8
8
  "name": "Adapt Toolkit"
9
9
  },
package/dist/index.js CHANGED
@@ -22429,7 +22429,7 @@ var StreamableHTTPServerTransport = class {
22429
22429
  // src/index.ts
22430
22430
  import { resolve as resolve2, join as join2, dirname as dirname2, isAbsolute } from "node:path";
22431
22431
  import { fileURLToPath } from "node:url";
22432
- import { randomBytes, randomUUID } from "node:crypto";
22432
+ import { randomBytes, randomInt, randomUUID } from "node:crypto";
22433
22433
  import { createServer as createHttpServer } from "node:http";
22434
22434
  import * as fs2 from "node:fs";
22435
22435
  import { brotliCompressSync, brotliDecompressSync, constants as zlibConstants } from "node:zlib";
@@ -22512,7 +22512,7 @@ function writeIdentityFile(target, opts, overwrite = false) {
22512
22512
  }
22513
22513
 
22514
22514
  // src/index.ts
22515
- var VERSION = true ? "0.11.3" : "0.0.0-dev";
22515
+ var VERSION = true ? "0.11.5" : "0.0.0-dev";
22516
22516
  var CONFIG = loadConfig();
22517
22517
  var STATE_DIR = CONFIG.stateDir;
22518
22518
  var BROKER_URL = CONFIG.brokerUrl;
@@ -22668,7 +22668,8 @@ function describeIdentity(id) {
22668
22668
  bio: v.Reduce("bio").Visualize(),
22669
22669
  roleId: v.Reduce("role_id").Visualize(),
22670
22670
  rootCid: v.Reduce("root_cid").Visualize(),
22671
- rootName: v.Reduce("root_name").Visualize()
22671
+ rootName: v.Reduce("root_name").Visualize(),
22672
+ monitoringEnabled: v.Reduce("monitoring_enabled").GetBoolean()
22672
22673
  };
22673
22674
  }
22674
22675
  async function delegateRole(root, role) {
@@ -22735,6 +22736,282 @@ async function sendViaLocalBook(id, contact, text) {
22735
22736
  });
22736
22737
  return `"${entry.name}" was not a contact yet \u2014 connected via the local contact book and sent the message with the introduction. If "${entry.name}" requires approval for local introductions, delivery completes once they approve.`;
22737
22738
  }
22739
+ function monitoringStatus(id) {
22740
+ const v = readonlyTx(id, "::actor::get_monitoring_status");
22741
+ return {
22742
+ enabled: v.Reduce("monitoring_enabled").GetBoolean(),
22743
+ proxyCid: v.Reduce("proxy_cid").Visualize(),
22744
+ proxyPending: v.Reduce("proxy_pending").GetBoolean(),
22745
+ copiesQueued: parseInt(v.Reduce("copies_queued").Visualize(), 10) || 0,
22746
+ controlQueued: parseInt(v.Reduce("control_queued").Visualize(), 10) || 0
22747
+ };
22748
+ }
22749
+ async function setAgentMonitoring(root, role, enabled) {
22750
+ if (enabled) {
22751
+ const rootAd = exportAdBlob(root);
22752
+ await mutatingTx(role, "::actor::connect_sibling", {
22753
+ name: root.name,
22754
+ target_ad: role.pw.packet.NewBinaryFromBuffer(rootAd)
22755
+ });
22756
+ }
22757
+ const roleAd = exportAdBlob(role);
22758
+ const authData = await mutatingTx(root, "::actor::sign_monitoring_auth", {
22759
+ role_ad: root.pw.packet.NewBinaryFromBuffer(roleAd),
22760
+ enabled
22761
+ });
22762
+ const authBlob = Buffer.from(authData.Reduce("auth").GetBinary());
22763
+ await mutatingTx(role, "::actor::set_monitoring", {
22764
+ auth: role.pw.packet.NewBinaryFromBuffer(authBlob)
22765
+ });
22766
+ log(`[${role.name}] monitoring ${enabled ? "enabled" : "disabled"} (authorized by root "${root.name}")`);
22767
+ }
22768
+ async function sendControl(id, contactRef, payload) {
22769
+ await mutatingTx(id, "::a2a_control::send_control", {
22770
+ contact: contactRef,
22771
+ payload: JSON.stringify(payload)
22772
+ });
22773
+ }
22774
+ function renderCopies(v) {
22775
+ const out = [];
22776
+ if (v.IsNil()) return out;
22777
+ for (let i = 0; ; i++) {
22778
+ const m = v.Reduce(i);
22779
+ if (m.IsNil()) break;
22780
+ out.push({
22781
+ source_cid: m.Reduce("source_cid").Visualize(),
22782
+ source_name: m.Reduce("source_name").Visualize(),
22783
+ direction: m.Reduce("direction").Visualize(),
22784
+ peer_cid: m.Reduce("peer_cid").Visualize(),
22785
+ peer_name: m.Reduce("peer_name").Visualize(),
22786
+ date: m.Reduce("date").Visualize(),
22787
+ body: m.Reduce("body").Visualize()
22788
+ });
22789
+ }
22790
+ return out;
22791
+ }
22792
+ function renderControlRequests(v) {
22793
+ const out = [];
22794
+ if (v.IsNil()) return out;
22795
+ for (let i = 0; ; i++) {
22796
+ const m = v.Reduce(i);
22797
+ if (m.IsNil()) break;
22798
+ out.push({
22799
+ senderCid: m.Reduce("sender_cid").Visualize(),
22800
+ senderName: m.Reduce("sender_name").Visualize(),
22801
+ payload: m.Reduce("payload").Visualize(),
22802
+ date: m.Reduce("date").Visualize()
22803
+ });
22804
+ }
22805
+ return out;
22806
+ }
22807
+ var forwardBusy = /* @__PURE__ */ new Set();
22808
+ async function forwardMonitoring(root) {
22809
+ if (forwardBusy.has(root.name)) return;
22810
+ forwardBusy.add(root.name);
22811
+ try {
22812
+ const st = monitoringStatus(root);
22813
+ if (!st.proxyCid || st.copiesQueued === 0) return;
22814
+ const data = await mutatingTx(root, "::actor::get_monitoring_copies", {});
22815
+ const copies = renderCopies(data.Reduce("copies"));
22816
+ if (copies.length === 0) return;
22817
+ await sendControl(root, st.proxyCid, { v: 1, t: "monitoring", copies });
22818
+ } catch (err) {
22819
+ log(`[${root.name}] monitoring forward failed:`, String(err));
22820
+ } finally {
22821
+ forwardBusy.delete(root.name);
22822
+ }
22823
+ }
22824
+ function listAgentsFor(root) {
22825
+ const agents = [];
22826
+ for (const id of identities.values()) {
22827
+ if (id.name === root.name) continue;
22828
+ const info = describeIdentity(id);
22829
+ if (info.rootCid !== root.cid) continue;
22830
+ agents.push({
22831
+ name: id.name,
22832
+ cid: id.cid,
22833
+ role_id: info.roleId,
22834
+ bio: info.bio,
22835
+ monitoring: info.monitoringEnabled
22836
+ });
22837
+ }
22838
+ return agents;
22839
+ }
22840
+ function findAgentOf(root, ref) {
22841
+ const id = identities.get(ref) ?? [...identities.values()].find((i) => i.cid === ref);
22842
+ if (!id || id.name === root.name) return null;
22843
+ return describeIdentity(id).rootCid === root.cid ? id : null;
22844
+ }
22845
+ function deleteIdentityCompletely(id) {
22846
+ try {
22847
+ wrapper.remove_packet(id.cid);
22848
+ } catch (err) {
22849
+ log(`remove_packet(${id.cid}) failed:`, String(err));
22850
+ }
22851
+ identities.delete(id.name);
22852
+ try {
22853
+ unpublishFromBook(id.name);
22854
+ } catch (err) {
22855
+ log(`failed to unpublish "${id.name}" from the contact book:`, String(err));
22856
+ }
22857
+ const holder = bindingOwner.get(id.name);
22858
+ if (holder) {
22859
+ bindingOwner.delete(id.name);
22860
+ sessionBinding.delete(holder);
22861
+ persistBindings();
22862
+ }
22863
+ if (id.name === rootName) {
22864
+ rootName = null;
22865
+ clearRootMarker();
22866
+ }
22867
+ try {
22868
+ fs2.rmSync(id.dir, { recursive: true, force: true });
22869
+ } catch (err) {
22870
+ return `deleting ${id.dir} failed: ${String(err)}`;
22871
+ }
22872
+ return null;
22873
+ }
22874
+ async function handleControlRequest(root, req) {
22875
+ let msg;
22876
+ try {
22877
+ const parsed = JSON.parse(req.payload);
22878
+ if (!parsed || typeof parsed !== "object") throw new Error("not an object");
22879
+ msg = parsed;
22880
+ } catch {
22881
+ log(`[${root.name}] dropping unparseable control request from ${req.senderName}`);
22882
+ return;
22883
+ }
22884
+ if (msg.v !== 1 || typeof msg.t !== "string") {
22885
+ log(`[${root.name}] dropping control request with unknown envelope from ${req.senderName}`);
22886
+ return;
22887
+ }
22888
+ const reply = async (data) => {
22889
+ try {
22890
+ await sendControl(root, req.senderCid, { v: 1, t: "res", id: msg.id ?? null, req: msg.t, ...data });
22891
+ } catch (err) {
22892
+ log(`[${root.name}] control reply to ${req.senderName} failed:`, String(err));
22893
+ }
22894
+ };
22895
+ try {
22896
+ if (msg.t === "bind") {
22897
+ const data = await mutatingTx(root, "::actor::verify_proxy_code", {
22898
+ code: String(msg.code ?? ""),
22899
+ sender: req.senderCid
22900
+ });
22901
+ if (!data.Reduce("verified").GetBoolean()) {
22902
+ const reason = data.Reduce("reason").Visualize();
22903
+ log(`[${root.name}] proxy bind attempt from ${req.senderName} rejected (${reason})`);
22904
+ await reply({ ok: false, error: reason });
22905
+ return;
22906
+ }
22907
+ appendNotifyLog(root, { event: "monitoring_proxy_bound", from: req.senderName });
22908
+ log(`[${root.name}] monitoring proxy bound: ${req.senderName} (${req.senderCid})`);
22909
+ await reply({ ok: true, root: { name: root.name, cid: root.cid }, agents: listAgentsFor(root) });
22910
+ await forwardMonitoring(root);
22911
+ return;
22912
+ }
22913
+ const st = monitoringStatus(root);
22914
+ if (!st.proxyCid || st.proxyCid !== req.senderCid) {
22915
+ await reply({ ok: false, error: "not_authorized" });
22916
+ return;
22917
+ }
22918
+ switch (msg.t) {
22919
+ case "list_agents": {
22920
+ await reply({ ok: true, root: { name: root.name, cid: root.cid }, agents: listAgentsFor(root) });
22921
+ return;
22922
+ }
22923
+ case "create_agent": {
22924
+ const name = String(msg.name ?? "").trim();
22925
+ const bio = String(msg.bio ?? "");
22926
+ const bad = validateName(name);
22927
+ if (bad) {
22928
+ await reply({ ok: false, error: bad });
22929
+ return;
22930
+ }
22931
+ if (identities.has(name)) {
22932
+ await reply({ ok: false, error: `an identity named "${name}" already exists` });
22933
+ return;
22934
+ }
22935
+ const agent = await provisionIdentity(name);
22936
+ if (bio) await mutatingTx(agent, "::a2a_messaging::set_my_bio", { bio });
22937
+ await delegateRole(root, agent);
22938
+ await reply({ ok: true, agents: listAgentsFor(root) });
22939
+ return;
22940
+ }
22941
+ case "update_role": {
22942
+ const agent = findAgentOf(root, String(msg.agent ?? ""));
22943
+ if (!agent) {
22944
+ await reply({ ok: false, error: "no such agent under this root" });
22945
+ return;
22946
+ }
22947
+ await mutatingTx(agent, "::a2a_messaging::set_my_bio", { bio: String(msg.bio ?? "") });
22948
+ await reply({ ok: true, agents: listAgentsFor(root) });
22949
+ return;
22950
+ }
22951
+ case "set_monitoring": {
22952
+ const agent = findAgentOf(root, String(msg.agent ?? ""));
22953
+ if (!agent) {
22954
+ await reply({ ok: false, error: "no such agent under this root" });
22955
+ return;
22956
+ }
22957
+ await setAgentMonitoring(root, agent, Boolean(msg.enabled));
22958
+ await reply({ ok: true, agents: listAgentsFor(root) });
22959
+ return;
22960
+ }
22961
+ case "contact_agent": {
22962
+ const agent = findAgentOf(root, String(msg.agent ?? ""));
22963
+ if (!agent) {
22964
+ await reply({ ok: false, error: "no such agent under this root" });
22965
+ return;
22966
+ }
22967
+ const inv = await mutatingTx(agent, "::a2a_messaging::generate_invite", {});
22968
+ const blob = packInvite(Buffer.from(inv.Reduce("invite").GetBinary()));
22969
+ await reply({ ok: true, agent: agent.name, invite: blob });
22970
+ return;
22971
+ }
22972
+ case "remove_agent": {
22973
+ const agent = findAgentOf(root, String(msg.agent ?? ""));
22974
+ if (!agent) {
22975
+ await reply({ ok: false, error: "no such agent under this root" });
22976
+ return;
22977
+ }
22978
+ const fail = deleteIdentityCompletely(agent);
22979
+ if (fail) {
22980
+ await reply({ ok: false, error: fail });
22981
+ return;
22982
+ }
22983
+ await reply({ ok: true, agents: listAgentsFor(root) });
22984
+ return;
22985
+ }
22986
+ default:
22987
+ await reply({ ok: false, error: `unknown request type "${msg.t}"` });
22988
+ }
22989
+ } catch (err) {
22990
+ await reply({ ok: false, error: String(err) });
22991
+ }
22992
+ }
22993
+ var controlBusy = /* @__PURE__ */ new Set();
22994
+ async function processControlRequests(root) {
22995
+ if (controlBusy.has(root.name)) return;
22996
+ controlBusy.add(root.name);
22997
+ try {
22998
+ for (; ; ) {
22999
+ const data = await mutatingTx(root, "::actor::get_control_requests", {});
23000
+ const reqs = renderControlRequests(data.Reduce("requests"));
23001
+ if (reqs.length === 0) return;
23002
+ for (const req of reqs) {
23003
+ await handleControlRequest(root, req);
23004
+ }
23005
+ }
23006
+ } catch (err) {
23007
+ log(`[${root.name}] control dispatch failed:`, String(err));
23008
+ } finally {
23009
+ controlBusy.delete(root.name);
23010
+ }
23011
+ if (identities.has(root.name) && monitoringStatus(root).controlQueued > 0) {
23012
+ return processControlRequests(root);
23013
+ }
23014
+ }
22738
23015
  async function ensureRegistrar() {
22739
23016
  fs2.mkdirSync(bookDir(), { recursive: true });
22740
23017
  let seed;
@@ -22897,6 +23174,12 @@ function wireHandlers(id) {
22897
23174
  process.nextTick(
22898
23175
  () => pushNotification(id.name, `[${id.name}] "${name}" queued a message awaiting introduction approval (${queued} queued).`)
22899
23176
  );
23177
+ } else if (event === "control_request") {
23178
+ const from = payload.Reduce("sender_name").Visualize();
23179
+ log(`[${id.name}] control request queued by ${from}`);
23180
+ process.nextTick(() => void processControlRequests(id));
23181
+ } else if (event === "monitoring_copy") {
23182
+ process.nextTick(() => void forwardMonitoring(id));
22900
23183
  }
22901
23184
  return;
22902
23185
  }
@@ -22962,7 +23245,7 @@ async function provisionIdentity(name, opts = { exposeLocal: true, localAutoAcce
22962
23245
  const seed = randomBytes(24).toString("hex");
22963
23246
  fs2.writeFileSync(seedPath(dir), seed, { mode: 384 });
22964
23247
  const id = await createPacket(name, seed, dir);
22965
- await mutatingTx(id, "::actor::set_my_name", { name });
23248
+ await mutatingTx(id, "::a2a_messaging::set_my_name", { name });
22966
23249
  await pinRegistrar(id);
22967
23250
  if (!opts.localAutoAccept) {
22968
23251
  await mutatingTx(id, "::actor::set_local_policy", { auto_accept: false });
@@ -23034,6 +23317,16 @@ async function bootWrapper() {
23034
23317
  clearRootMarker();
23035
23318
  }
23036
23319
  if (rootName) log(`root identity: ${rootName}`);
23320
+ const root = rootName ? identities.get(rootName) : void 0;
23321
+ if (root) {
23322
+ try {
23323
+ const st = monitoringStatus(root);
23324
+ if (st.controlQueued > 0) void processControlRequests(root);
23325
+ else if (st.copiesQueued > 0) void forwardMonitoring(root);
23326
+ } catch (err) {
23327
+ log(`boot-time monitoring/control drain failed:`, String(err));
23328
+ }
23329
+ }
23037
23330
  persistBindings();
23038
23331
  }
23039
23332
  function resolveBound(sessionId) {
@@ -23174,7 +23467,7 @@ function createMcpServer(getSessionId) {
23174
23467
  if (identities.has(name)) return textResult(`create_identity failed: an identity named "${name}" already exists.`, true);
23175
23468
  try {
23176
23469
  const id = await provisionIdentity(name, { exposeLocal: expose_local, localAutoAccept: local_auto_accept });
23177
- if (bio) await mutatingTx(id, "::actor::set_my_bio", { bio });
23470
+ if (bio) await mutatingTx(id, "::a2a_messaging::set_my_bio", { bio });
23178
23471
  let hierarchy = "";
23179
23472
  const root = rootName ? identities.get(rootName) : void 0;
23180
23473
  if (root) {
@@ -23216,7 +23509,7 @@ Ask the user: do you want to arm a message monitor for "${name}"? If yes, use: M
23216
23509
  }
23217
23510
  try {
23218
23511
  const id = await provisionIdentity(name, { exposeLocal: expose_local, localAutoAccept: local_auto_accept });
23219
- if (bio) await mutatingTx(id, "::actor::set_my_bio", { bio });
23512
+ if (bio) await mutatingTx(id, "::a2a_messaging::set_my_bio", { bio });
23220
23513
  rootName = name;
23221
23514
  writeRootMarker(name);
23222
23515
  const adopted = [];
@@ -23391,31 +23684,9 @@ Bio: ${info.bio}` : "";
23391
23684
  );
23392
23685
  }
23393
23686
  }
23394
- try {
23395
- wrapper.remove_packet(id.cid);
23396
- } catch (err) {
23397
- log(`remove_packet(${id.cid}) failed:`, String(err));
23398
- }
23399
- identities.delete(name);
23400
- try {
23401
- unpublishFromBook(name);
23402
- } catch (err) {
23403
- log(`failed to unpublish "${name}" from the contact book:`, String(err));
23404
- }
23405
- const holder = bindingOwner.get(name);
23406
- if (holder) {
23407
- bindingOwner.delete(name);
23408
- sessionBinding.delete(holder);
23409
- persistBindings();
23410
- }
23411
- if (name === rootName) {
23412
- rootName = null;
23413
- clearRootMarker();
23414
- }
23415
- try {
23416
- fs2.rmSync(id.dir, { recursive: true, force: true });
23417
- } catch (err) {
23418
- return textResult(`Identity "${name}" removed from memory, but deleting ${id.dir} failed: ${String(err)}`, true);
23687
+ const fail = deleteIdentityCompletely(id);
23688
+ if (fail) {
23689
+ return textResult(`Identity "${name}" removed from memory, but ${fail}`, true);
23419
23690
  }
23420
23691
  return textResult(`Removed identity "${name}" and its state.`);
23421
23692
  }
@@ -23444,7 +23715,7 @@ ${inbox.map((m) => fmtMsg(m)).join("\n")}`;
23444
23715
  try {
23445
23716
  const targ = {};
23446
23717
  if (name) targ.name = name;
23447
- const data = await mutatingTx(id, "::actor::generate_invite", targ);
23718
+ const data = await mutatingTx(id, "::a2a_messaging::generate_invite", targ);
23448
23719
  const blob = packInvite(Buffer.from(data.Reduce("invite").GetBinary()));
23449
23720
  const heading = name ? `Invite for "${name}" created.` : "Invite created \u2014 the contact will be registered under the name the recipient announces when accepting.";
23450
23721
  return textResult(
@@ -23478,7 +23749,7 @@ ${blob}`
23478
23749
  const blobValue = id.pw.packet.NewBinaryFromBuffer(buf);
23479
23750
  const targ = { invite: blobValue };
23480
23751
  if (name) targ.name = name;
23481
- const data = await mutatingTx(id, "::actor::add_contact", targ);
23752
+ const data = await mutatingTx(id, "::a2a_messaging::add_contact", targ);
23482
23753
  const added = data.Reduce("added").Visualize();
23483
23754
  const cid = data.Reduce("container_id").Visualize();
23484
23755
  const roleId = data.Reduce("role_id").Visualize();
@@ -23499,9 +23770,9 @@ ${blob}`
23499
23770
  const { id, err } = boundOr();
23500
23771
  if (err) return err;
23501
23772
  try {
23502
- const contacts = renderContacts(readonlyTx(id, "::actor::list_contacts"));
23773
+ const contacts = renderContacts(readonlyTx(id, "::a2a_messaging::list_contacts"));
23503
23774
  const pending = renderPending(readonlyTx(id, "::actor::list_pending_introductions"));
23504
- const roots = renderContactRoots(readonlyTx(id, "::actor::list_contact_roots"));
23775
+ const roots = renderContactRoots(readonlyTx(id, "::a2a_messaging::list_contact_roots"));
23505
23776
  const lines = [];
23506
23777
  lines.push(
23507
23778
  contacts.length === 0 ? "No contacts yet." : `Contacts (${contacts.length}):
@@ -23576,7 +23847,7 @@ ${lines.join("\n")}`);
23576
23847
  const { id, err } = boundOr();
23577
23848
  if (err) return err;
23578
23849
  try {
23579
- await mutatingTx(id, "::actor::set_my_bio", { bio });
23850
+ await mutatingTx(id, "::a2a_messaging::set_my_bio", { bio });
23580
23851
  let refreshed = 0;
23581
23852
  if (id.name === rootName) {
23582
23853
  for (const other of identities.values()) {
@@ -23638,7 +23909,7 @@ ${lines.join("\n")}`);
23638
23909
  const { id, err } = boundOr();
23639
23910
  if (err) return err;
23640
23911
  try {
23641
- await mutatingTx(id, "::actor::send_message", { contact, text });
23912
+ await mutatingTx(id, "::a2a_messaging::send_message", { contact, text });
23642
23913
  return textResult(`Message sent to "${contact}".`);
23643
23914
  } catch (e) {
23644
23915
  if (!/Unknown contact/.test(String(e))) {
@@ -23662,7 +23933,7 @@ ${lines.join("\n")}`);
23662
23933
  const { id, err } = boundOr();
23663
23934
  if (err) return err;
23664
23935
  try {
23665
- const data = await mutatingTx(id, "::actor::remove_contact", { contact });
23936
+ const data = await mutatingTx(id, "::a2a_messaging::remove_contact", { contact });
23666
23937
  const name = data.Reduce("removed").Visualize();
23667
23938
  const cid = data.Reduce("container_id").Visualize();
23668
23939
  return textResult(`Removed contact "${name}" (${cid}).`);
@@ -23731,6 +24002,97 @@ These are now marked processed (auto-GC'd later). To hand any back to another se
23731
24002
  }
23732
24003
  }
23733
24004
  );
24005
+ const rootOr = () => {
24006
+ const root = rootName ? identities.get(rootName) : void 0;
24007
+ if (!root) {
24008
+ return { err: textResult("No root identity exists on this host \u2014 create one with create_root_identity first.", true) };
24009
+ }
24010
+ return { root };
24011
+ };
24012
+ server.tool(
24013
+ "enable_monitoring",
24014
+ "Enable monitoring on one of this host's agents (a role under the root identity): from now on the agent reports a copy of every message it sends or receives to the root, which forwards them to the bound browser proxy (see bind_monitoring_proxy). Authorized by a root-signed blob the role verifies against its delegation chain. Forward-only: past messages are never reported.",
24015
+ { agent: external_exports.string().min(1).describe("Agent (role) name or container id.") },
24016
+ async ({ agent }) => {
24017
+ const { root, err } = rootOr();
24018
+ if (err) return err;
24019
+ const role = findAgentOf(root, agent);
24020
+ if (!role) return textResult(`enable_monitoring failed: "${agent}" is not a role under root "${root.name}".`, true);
24021
+ try {
24022
+ await setAgentMonitoring(root, role, true);
24023
+ return textResult(`Monitoring enabled on "${role.name}" \u2014 its message traffic now reports to root "${root.name}".`);
24024
+ } catch (e) {
24025
+ return textResult(`enable_monitoring failed: ${String(e)}`, true);
24026
+ }
24027
+ }
24028
+ );
24029
+ server.tool(
24030
+ "disable_monitoring",
24031
+ "Disable monitoring on one of this host's agents (see enable_monitoring).",
24032
+ { agent: external_exports.string().min(1).describe("Agent (role) name or container id.") },
24033
+ async ({ agent }) => {
24034
+ const { root, err } = rootOr();
24035
+ if (err) return err;
24036
+ const role = findAgentOf(root, agent);
24037
+ if (!role) return textResult(`disable_monitoring failed: "${agent}" is not a role under root "${root.name}".`, true);
24038
+ try {
24039
+ await setAgentMonitoring(root, role, false);
24040
+ return textResult(`Monitoring disabled on "${role.name}".`);
24041
+ } catch (e) {
24042
+ return textResult(`disable_monitoring failed: ${String(e)}`, true);
24043
+ }
24044
+ }
24045
+ );
24046
+ server.tool(
24047
+ "bind_monitoring_proxy",
24048
+ "Start binding a browser (messenger) account as this host's monitoring & control proxy. PREREQUISITE: the browser account must already be a contact of the ROOT identity (invite exchange). This generates a 6-digit code (5-minute expiry, 3 attempts) bound to that contact and shows it HERE \u2014 read it to the user, who enters it in the messenger's Control Panel. On a successful code verification the contact becomes the monitoring proxy: it receives the monitoring feed and may manage agents (create, edit bios, toggle monitoring, request invites) through the root.",
24049
+ { contact: external_exports.string().min(1).describe("The root's contact (name or container id) to bind as the proxy.") },
24050
+ async ({ contact }) => {
24051
+ const { root, err } = rootOr();
24052
+ if (err) return err;
24053
+ try {
24054
+ const code = String(randomInt(0, 1e6)).padStart(6, "0");
24055
+ const data = await mutatingTx(root, "::actor::set_proxy_pending", { code, proxy: contact });
24056
+ const cid = data.Reduce("proxy_cid").Visualize();
24057
+ return textResult(
24058
+ `Proxy binding started for contact "${contact}" (${cid}).
24059
+
24060
+ Verification code: ${code}
24061
+
24062
+ Tell the user to enter this code in the messenger's Control Panel within 5 minutes (3 attempts). Do NOT send the code over a2adapt \u2014 it must travel out-of-band (this terminal counts).`
24063
+ );
24064
+ } catch (e) {
24065
+ return textResult(`bind_monitoring_proxy failed: ${String(e)}`, true);
24066
+ }
24067
+ }
24068
+ );
24069
+ server.tool(
24070
+ "get_monitoring_status",
24071
+ "Report the monitoring & control state of this host: the root's bound proxy (if any), a pending proxy verification, queued copies/requests, and which agents have monitoring enabled.",
24072
+ {},
24073
+ async () => {
24074
+ const { root, err } = rootOr();
24075
+ if (err) return err;
24076
+ try {
24077
+ const st = monitoringStatus(root);
24078
+ const lines = [];
24079
+ lines.push(`Root "${root.name}" (${root.cid}):`);
24080
+ lines.push(st.proxyCid ? `\u2022 monitoring proxy bound: ${st.proxyCid}` : "\u2022 no monitoring proxy bound");
24081
+ if (st.proxyPending) lines.push("\u2022 a proxy code verification is pending");
24082
+ if (st.copiesQueued > 0) lines.push(`\u2022 ${st.copiesQueued} monitoring cop${st.copiesQueued === 1 ? "y" : "ies"} queued for forwarding`);
24083
+ if (st.controlQueued > 0) lines.push(`\u2022 ${st.controlQueued} control request(s) queued`);
24084
+ const agents = listAgentsFor(root);
24085
+ lines.push("");
24086
+ lines.push(
24087
+ agents.length === 0 ? "No agents (roles) under this root." : `Agents (${agents.length}):
24088
+ ${agents.map((a) => `\u2022 ${a.name} \u2014 monitoring ${a.monitoring ? "ON" : "off"}${a.bio ? ` \u2014 ${a.bio}` : ""}`).join("\n")}`
24089
+ );
24090
+ return textResult(lines.join("\n"));
24091
+ } catch (e) {
24092
+ return textResult(`get_monitoring_status failed: ${String(e)}`, true);
24093
+ }
24094
+ }
24095
+ );
23734
24096
  return server;
23735
24097
  }
23736
24098
  function readBody(req) {