@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.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/index.js +400 -38
- package/dist/mufl_code/D317A840D97E3B17E4EC644D50BDBB19DE3B78F9941C25853E1F86164A234593.muflo +0 -0
- package/dist/mufl_code/actor.mu +517 -451
- package/package.json +1 -1
- package/dist/mufl_code/7127B9740290EA8B2F30AFAE251198357D780A81DBF5EF30FE7DD9B66A510C21.muflo +0 -0
|
@@ -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.
|
|
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.
|
|
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, "::
|
|
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, "::
|
|
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, "::
|
|
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
|
-
|
|
23395
|
-
|
|
23396
|
-
|
|
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, "::
|
|
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, "::
|
|
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, "::
|
|
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, "::
|
|
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, "::
|
|
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, "::
|
|
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, "::
|
|
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) {
|