@agentvault/agentvault 0.15.2 → 0.16.0

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/dist/index.js CHANGED
@@ -45348,6 +45348,50 @@ var init_scan_engine = __esm({
45348
45348
  * Runs api_keys, pii_*, prompt_injection, and shell_injection checks
45349
45349
  * regardless of rule direction.
45350
45350
  */
45351
+ /**
45352
+ * Scan a SKILL.md file for policy violations.
45353
+ * Like scanWorkspaceFile but skips prompt_injection on instruction body
45354
+ * (skills legitimately describe AI behaviors that look like injection).
45355
+ * Checks: api_keys (block), shell_injection (block), pii (flag).
45356
+ */
45357
+ static scanSkillMd(content) {
45358
+ const violations = [];
45359
+ let blocked = false;
45360
+ let flagged = false;
45361
+ const checks = [
45362
+ { id: "api_keys", action: "block" },
45363
+ { id: "shell_injection", action: "block" },
45364
+ { id: "pii_ssn", action: "flag" },
45365
+ { id: "pii_credit_card", action: "flag" },
45366
+ { id: "pii_email", action: "flag" }
45367
+ // Intentionally omits prompt_injection — SKILL.md instruction body
45368
+ // legitimately contains phrases like "you are now a..."
45369
+ ];
45370
+ for (const check2 of checks) {
45371
+ const patterns = BUILTIN_PATTERNS[check2.id];
45372
+ if (!patterns)
45373
+ continue;
45374
+ for (const p2 of patterns) {
45375
+ const regex = new RegExp(p2.source, p2.flags);
45376
+ if (regex.test(content)) {
45377
+ violations.push({
45378
+ rule_id: `skill_${check2.id}`,
45379
+ rule_name: check2.id,
45380
+ action: check2.action,
45381
+ scanner_type: "builtin",
45382
+ match_summary: `builtin:${check2.id}`
45383
+ });
45384
+ if (check2.action === "block")
45385
+ blocked = true;
45386
+ if (check2.action === "flag")
45387
+ flagged = true;
45388
+ break;
45389
+ }
45390
+ }
45391
+ }
45392
+ const status = blocked ? "blocked" : flagged ? "flagged" : "clean";
45393
+ return { status, violations };
45394
+ }
45351
45395
  static scanWorkspaceFile(content) {
45352
45396
  const violations = [];
45353
45397
  let blocked = false;
@@ -46452,7 +46496,8 @@ __export(http_handlers_exports, {
46452
46496
  handleActionRequest: () => handleActionRequest,
46453
46497
  handleDecisionRequest: () => handleDecisionRequest,
46454
46498
  handleSendRequest: () => handleSendRequest,
46455
- handleStatusRequest: () => handleStatusRequest
46499
+ handleStatusRequest: () => handleStatusRequest,
46500
+ handleTargetsRequest: () => handleTargetsRequest
46456
46501
  });
46457
46502
  async function handleSendRequest(parsed, channel) {
46458
46503
  const text = parsed.text;
@@ -46460,32 +46505,55 @@ async function handleSendRequest(parsed, channel) {
46460
46505
  return { status: 400, body: { ok: false, error: "Missing 'text' field" } };
46461
46506
  }
46462
46507
  try {
46508
+ let target;
46463
46509
  let a2aTarget = parsed.hub_address ?? parsed.a2a_address ?? parsed.a2aAddress;
46464
46510
  if (!a2aTarget && parsed.channel_id && typeof parsed.channel_id === "string") {
46465
46511
  const hubAddr = channel.resolveA2AChannelHub(parsed.channel_id);
46466
46512
  if (hubAddr) a2aTarget = hubAddr;
46467
46513
  }
46468
- const roomId = (typeof parsed.room_id === "string" ? parsed.room_id : void 0) ?? channel.lastInboundRoomId;
46469
46514
  if (a2aTarget && typeof a2aTarget === "string") {
46470
- await channel.sendToAgent(a2aTarget, text);
46471
- } else if (roomId) {
46472
- await channel.sendToRoom(roomId, text, {
46473
- messageType: parsed.message_type,
46474
- priority: parsed.priority,
46475
- metadata: parsed.metadata
46476
- });
46515
+ target = { kind: "a2a", hubAddress: a2aTarget };
46516
+ } else if (typeof parsed.room_id === "string") {
46517
+ target = { kind: "room", roomId: parsed.room_id };
46518
+ } else if (parsed.target === "context") {
46519
+ target = { kind: "context" };
46477
46520
  } else if (parsed.file_path && typeof parsed.file_path === "string") {
46478
- await channel.sendWithAttachment(text, parsed.file_path, {
46479
- topicId: parsed.topicId
46480
- });
46521
+ const receipt2 = await channel.deliver(
46522
+ { kind: "owner" },
46523
+ { type: "attachment", text, filePath: parsed.file_path },
46524
+ { topicId: parsed.topicId }
46525
+ );
46526
+ return {
46527
+ status: receipt2.ok ? 200 : 500,
46528
+ body: {
46529
+ ok: receipt2.ok,
46530
+ destination: receipt2.destination,
46531
+ ...receipt2.error ? { error: receipt2.error } : {}
46532
+ }
46533
+ };
46481
46534
  } else {
46482
- await channel.send(text, {
46483
- topicId: parsed.topicId,
46484
- messageType: parsed.message_type,
46485
- metadata: parsed.metadata
46486
- });
46535
+ target = { kind: "owner" };
46487
46536
  }
46488
- return { status: 200, body: { ok: true } };
46537
+ const receipt = await channel.deliver(
46538
+ target,
46539
+ { type: "text", text },
46540
+ {
46541
+ topicId: parsed.topicId,
46542
+ priority: parsed.priority,
46543
+ metadata: {
46544
+ ...parsed.metadata,
46545
+ ...parsed.message_type ? { message_type: parsed.message_type } : {}
46546
+ }
46547
+ }
46548
+ );
46549
+ return {
46550
+ status: receipt.ok ? 200 : 500,
46551
+ body: {
46552
+ ok: receipt.ok,
46553
+ destination: receipt.destination,
46554
+ ...receipt.error ? { error: receipt.error } : {}
46555
+ }
46556
+ };
46489
46557
  } catch (err) {
46490
46558
  return { status: 500, body: { ok: false, error: String(err) } };
46491
46559
  }
@@ -46502,12 +46570,19 @@ async function handleActionRequest(parsed, channel) {
46502
46570
  detail: parsed.detail,
46503
46571
  estimated_cost: parsed.estimated_cost
46504
46572
  };
46505
- if (parsed.room_id && typeof parsed.room_id === "string") {
46506
- await channel.sendActionConfirmationToRoom(parsed.room_id, confirmation);
46507
- } else {
46508
- await channel.sendActionConfirmation(confirmation);
46509
- }
46510
- return { status: 200, body: { ok: true } };
46573
+ const target = parsed.room_id && typeof parsed.room_id === "string" ? { kind: "room", roomId: parsed.room_id } : { kind: "owner" };
46574
+ const receipt = await channel.deliver(
46575
+ target,
46576
+ { type: "action_confirmation", confirmation }
46577
+ );
46578
+ return {
46579
+ status: receipt.ok ? 200 : 500,
46580
+ body: {
46581
+ ok: receipt.ok,
46582
+ destination: receipt.destination,
46583
+ ...receipt.error ? { error: receipt.error } : {}
46584
+ }
46585
+ };
46511
46586
  } catch (err) {
46512
46587
  return { status: 500, body: { ok: false, error: String(err) } };
46513
46588
  }
@@ -46551,6 +46626,16 @@ function handleStatusRequest(channel) {
46551
46626
  }
46552
46627
  };
46553
46628
  }
46629
+ function handleTargetsRequest(channel) {
46630
+ return {
46631
+ status: 200,
46632
+ body: {
46633
+ ok: true,
46634
+ targets: channel.listTargets(),
46635
+ context: channel.lastInboundRoomId ? { kind: "room", roomId: channel.lastInboundRoomId } : { kind: "owner" }
46636
+ }
46637
+ };
46638
+ }
46554
46639
  var init_http_handlers = __esm({
46555
46640
  "src/http-handlers.ts"() {
46556
46641
  "use strict";
@@ -46727,7 +46812,7 @@ function migratePersistedState(raw) {
46727
46812
  messageHistory: []
46728
46813
  };
46729
46814
  }
46730
- var POLL_INTERVAL_MS, RECONNECT_BASE_MS, RECONNECT_MAX_MS, PENDING_POLL_INTERVAL_MS, SecureChannel;
46815
+ var ROOM_AGENT_TYPES, POLL_INTERVAL_MS, RECONNECT_BASE_MS, RECONNECT_MAX_MS, PENDING_POLL_INTERVAL_MS, SecureChannel;
46731
46816
  var init_channel = __esm({
46732
46817
  async "src/channel.ts"() {
46733
46818
  "use strict";
@@ -46736,6 +46821,13 @@ var init_channel = __esm({
46736
46821
  await init_crypto_helpers();
46737
46822
  await init_state();
46738
46823
  init_transport2();
46824
+ ROOM_AGENT_TYPES = /* @__PURE__ */ new Set([
46825
+ "message",
46826
+ "text",
46827
+ "decision_request",
46828
+ "decision_response",
46829
+ "artifact_share"
46830
+ ]);
46739
46831
  POLL_INTERVAL_MS = 6e3;
46740
46832
  RECONNECT_BASE_MS = 1e3;
46741
46833
  RECONNECT_MAX_MS = 3e4;
@@ -47523,6 +47615,171 @@ var init_channel = __esm({
47523
47615
  metadata
47524
47616
  });
47525
47617
  }
47618
+ // --- Unified Delivery Protocol ---
47619
+ /**
47620
+ * Canonical message dispatcher. ALL outbound messages should flow through this method.
47621
+ * Routes based on explicit target — never silently falls back to a room.
47622
+ */
47623
+ async deliver(target, content, options) {
47624
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
47625
+ if (this._state === "idle" || this._state === "error") {
47626
+ return {
47627
+ ok: false,
47628
+ destination: { kind: "owner" },
47629
+ error: `Channel is in ${this._state} state`,
47630
+ timestamp: ts
47631
+ };
47632
+ }
47633
+ let resolved;
47634
+ if (target.kind === "context") {
47635
+ if (this._lastInboundRoomId) {
47636
+ resolved = { kind: "room", id: this._lastInboundRoomId };
47637
+ console.log(`[deliver] target=context\u2192room:${this._lastInboundRoomId.slice(0, 8)}...`);
47638
+ } else {
47639
+ resolved = { kind: "owner" };
47640
+ console.log(`[deliver] target=context\u2192owner`);
47641
+ }
47642
+ } else if (target.kind === "owner") {
47643
+ resolved = { kind: "owner" };
47644
+ } else if (target.kind === "room") {
47645
+ if (!this._persisted?.rooms?.[target.roomId]) {
47646
+ const err = `Room ${target.roomId} not found`;
47647
+ console.log(`[deliver] target=room:${target.roomId.slice(0, 8)}... content=${content.type} result=FAIL: ${err}`);
47648
+ return { ok: false, destination: { kind: "room", id: target.roomId }, error: err, timestamp: ts };
47649
+ }
47650
+ resolved = { kind: "room", id: target.roomId };
47651
+ } else if (target.kind === "a2a") {
47652
+ const channelEntry = this._persisted?.a2aChannels ? Object.values(this._persisted.a2aChannels).find((ch) => ch.hubAddress === target.hubAddress) : void 0;
47653
+ if (!channelEntry) {
47654
+ const err = `No A2A channel found for hub address: ${target.hubAddress}`;
47655
+ console.log(`[deliver] target=a2a:${target.hubAddress} content=${content.type} result=FAIL: ${err}`);
47656
+ return { ok: false, destination: { kind: "a2a", id: target.hubAddress }, error: err, timestamp: ts };
47657
+ }
47658
+ resolved = { kind: "a2a", id: target.hubAddress };
47659
+ } else {
47660
+ return { ok: false, destination: { kind: "owner" }, error: "Unknown target kind", timestamp: ts };
47661
+ }
47662
+ try {
47663
+ let decisionId;
47664
+ if (content.type === "text") {
47665
+ if (resolved.kind === "room") {
47666
+ await this.sendToRoom(resolved.id, content.text, {
47667
+ messageType: options?.metadata?.message_type,
47668
+ priority: options?.priority,
47669
+ metadata: options?.metadata
47670
+ });
47671
+ } else if (resolved.kind === "a2a") {
47672
+ await this.sendToAgent(resolved.id, content.text, {
47673
+ parentSpanId: options?.parentSpanId
47674
+ });
47675
+ } else {
47676
+ await this.send(content.text, {
47677
+ conversationId: options?.conversationId,
47678
+ topicId: options?.topicId,
47679
+ messageType: options?.metadata?.message_type,
47680
+ priority: options?.priority,
47681
+ metadata: options?.metadata
47682
+ });
47683
+ }
47684
+ } else if (content.type === "decision_request") {
47685
+ if (resolved.kind !== "owner") {
47686
+ const err = "Decision requests can only be sent to owner";
47687
+ console.log(`[deliver] target=${resolved.kind}:${resolved.id} content=decision_request result=FAIL: ${err}`);
47688
+ return { ok: false, destination: resolved, error: err, timestamp: ts };
47689
+ }
47690
+ decisionId = await this.sendDecisionRequest(content.request);
47691
+ } else if (content.type === "status_alert") {
47692
+ if (resolved.kind === "room") {
47693
+ const envelope = {
47694
+ title: content.alert.title,
47695
+ message: content.alert.message,
47696
+ severity: content.alert.severity,
47697
+ timestamp: ts
47698
+ };
47699
+ if (content.alert.detail !== void 0) envelope.detail = content.alert.detail;
47700
+ if (content.alert.detailFormat !== void 0) envelope.detail_format = content.alert.detailFormat;
47701
+ if (content.alert.category !== void 0) envelope.category = content.alert.category;
47702
+ await this.sendToRoom(resolved.id, JSON.stringify(envelope), {
47703
+ messageType: "status_alert",
47704
+ priority: content.alert.severity === "error" || content.alert.severity === "critical" ? "high" : "normal",
47705
+ metadata: { severity: content.alert.severity }
47706
+ });
47707
+ } else if (resolved.kind === "owner") {
47708
+ await this.sendStatusAlert(content.alert);
47709
+ } else {
47710
+ return { ok: false, destination: resolved, error: "Status alerts cannot be sent to A2A targets", timestamp: ts };
47711
+ }
47712
+ } else if (content.type === "action_confirmation") {
47713
+ if (resolved.kind === "room") {
47714
+ await this.sendActionConfirmationToRoom(resolved.id, content.confirmation);
47715
+ } else if (resolved.kind === "owner") {
47716
+ await this.sendActionConfirmation(content.confirmation);
47717
+ } else {
47718
+ return { ok: false, destination: resolved, error: "Action confirmations cannot be sent to A2A targets", timestamp: ts };
47719
+ }
47720
+ } else if (content.type === "artifact") {
47721
+ if (resolved.kind !== "owner") {
47722
+ return { ok: false, destination: resolved, error: "Artifacts can only be sent to owner", timestamp: ts };
47723
+ }
47724
+ await this.sendArtifact(content.artifact);
47725
+ } else if (content.type === "attachment") {
47726
+ if (resolved.kind !== "owner") {
47727
+ return { ok: false, destination: resolved, error: "Attachments can only be sent to owner", timestamp: ts };
47728
+ }
47729
+ await this.sendWithAttachment(content.text, content.filePath, {
47730
+ topicId: options?.topicId
47731
+ });
47732
+ }
47733
+ const targetLabel = resolved.kind === "owner" ? "owner" : `${resolved.kind}:${resolved.id?.slice(0, 8)}...`;
47734
+ console.log(`[deliver] target=${targetLabel} content=${content.type} result=ok`);
47735
+ return {
47736
+ ok: true,
47737
+ destination: resolved,
47738
+ queued: this._state !== "ready",
47739
+ decisionId,
47740
+ timestamp: ts
47741
+ };
47742
+ } catch (err) {
47743
+ const targetLabel = resolved.kind === "owner" ? "owner" : `${resolved.kind}:${resolved.id?.slice(0, 8)}...`;
47744
+ const errMsg = err instanceof Error ? err.message : String(err);
47745
+ console.log(`[deliver] target=${targetLabel} content=${content.type} result=FAIL: ${errMsg}`);
47746
+ return { ok: false, destination: resolved, error: errMsg, timestamp: ts };
47747
+ }
47748
+ }
47749
+ /**
47750
+ * Returns all available delivery destinations with availability status.
47751
+ */
47752
+ listTargets() {
47753
+ const targets = [
47754
+ {
47755
+ kind: "owner",
47756
+ id: "owner",
47757
+ label: "Owner (direct)",
47758
+ available: this._state === "ready" && this._sessions.size > 0
47759
+ }
47760
+ ];
47761
+ if (this._persisted?.rooms) {
47762
+ for (const room of Object.values(this._persisted.rooms)) {
47763
+ targets.push({
47764
+ kind: "room",
47765
+ id: room.roomId,
47766
+ label: room.name || `Room ${room.roomId.slice(0, 8)}`,
47767
+ available: this._state === "ready" && room.conversationIds.length > 0
47768
+ });
47769
+ }
47770
+ }
47771
+ if (this._persisted?.a2aChannels) {
47772
+ for (const ch of Object.values(this._persisted.a2aChannels)) {
47773
+ targets.push({
47774
+ kind: "a2a",
47775
+ id: ch.hubAddress,
47776
+ label: `A2A: ${ch.hubAddress}`,
47777
+ available: this._state === "ready" && !!ch.session?.ratchetState
47778
+ });
47779
+ }
47780
+ }
47781
+ return targets;
47782
+ }
47526
47783
  _sendHeartbeat() {
47527
47784
  if (this._state !== "ready" || !this._heartbeatCallback) return;
47528
47785
  const status = this._heartbeatCallback();
@@ -47641,9 +47898,13 @@ var init_channel = __esm({
47641
47898
  const result = handlers.handleStatusRequest(this);
47642
47899
  res.writeHead(result.status, { "Content-Type": "application/json" });
47643
47900
  res.end(JSON.stringify(result.body));
47901
+ } else if (req.method === "GET" && req.url === "/targets") {
47902
+ const result = handlers.handleTargetsRequest(this);
47903
+ res.writeHead(result.status, { "Content-Type": "application/json" });
47904
+ res.end(JSON.stringify(result.body));
47644
47905
  } else {
47645
47906
  res.writeHead(404, { "Content-Type": "application/json" });
47646
- res.end(JSON.stringify({ ok: false, error: "Not found. Use POST /send, POST /decision, POST /action, or GET /status" }));
47907
+ res.end(JSON.stringify({ ok: false, error: "Not found. Use POST /send, POST /decision, POST /action, GET /status, or GET /targets" }));
47647
47908
  }
47648
47909
  });
47649
47910
  this._httpServer.listen(port, "127.0.0.1", () => {
@@ -49279,6 +49540,9 @@ ${messageText}`;
49279
49540
  messageType = "message";
49280
49541
  messageText = plaintext;
49281
49542
  }
49543
+ if (!ROOM_AGENT_TYPES.has(messageType)) {
49544
+ return;
49545
+ }
49282
49546
  if (!session.activated) {
49283
49547
  session.activated = true;
49284
49548
  console.log(
@@ -49297,7 +49561,9 @@ ${messageText}`;
49297
49561
  conversationId: convId,
49298
49562
  timestamp: msgData.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
49299
49563
  messageType,
49300
- roomId: msgData.room_id
49564
+ roomId: msgData.room_id,
49565
+ senderDeviceId: msgData.sender_device_id,
49566
+ roomName: this._persisted?.rooms?.[msgData.room_id]?.name
49301
49567
  };
49302
49568
  this.emit("room_message", {
49303
49569
  roomId: msgData.room_id,
@@ -49472,6 +49738,9 @@ ${messageText}`;
49472
49738
  messageType = "message";
49473
49739
  messageText = plaintext;
49474
49740
  }
49741
+ if (!ROOM_AGENT_TYPES.has(messageType)) {
49742
+ return;
49743
+ }
49475
49744
  if (msgData.message_id) {
49476
49745
  this._sendAck(msgData.message_id);
49477
49746
  }
@@ -49484,7 +49753,9 @@ ${messageText}`;
49484
49753
  conversationId: "",
49485
49754
  timestamp: msgData.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
49486
49755
  messageType,
49487
- roomId: msgData.room_id
49756
+ roomId: msgData.room_id,
49757
+ senderDeviceId: msgData.sender_device_id,
49758
+ roomName: this._persisted?.rooms?.[msgData.room_id]?.name
49488
49759
  };
49489
49760
  this.emit("room_message", {
49490
49761
  roomId: msgData.room_id,
@@ -49954,6 +50225,39 @@ ${messageText}`;
49954
50225
  }
49955
50226
  });
49956
50227
 
50228
+ // src/types.ts
50229
+ function parseTarget(raw) {
50230
+ let target = raw;
50231
+ if (target.startsWith("agentvault:")) {
50232
+ target = target.slice("agentvault:".length);
50233
+ }
50234
+ if (target.startsWith("agent:")) {
50235
+ target = "a2a:" + target.slice("agent:".length);
50236
+ }
50237
+ if (target === "owner" || target === "default") {
50238
+ return { kind: "owner" };
50239
+ }
50240
+ if (target === "context") {
50241
+ return { kind: "context" };
50242
+ }
50243
+ if (target.startsWith("room:")) {
50244
+ const roomId = target.slice("room:".length);
50245
+ if (!roomId) throw new Error(`Invalid room target: "${raw}" \u2014 missing room ID`);
50246
+ return { kind: "room", roomId };
50247
+ }
50248
+ if (target.startsWith("a2a:")) {
50249
+ const hubAddress = target.slice("a2a:".length);
50250
+ if (!hubAddress) throw new Error(`Invalid A2A target: "${raw}" \u2014 missing hub address`);
50251
+ return { kind: "a2a", hubAddress };
50252
+ }
50253
+ throw new Error(`Unrecognized delivery target: "${raw}". Use "owner", "room:<id>", "a2a:<addr>", or "context".`);
50254
+ }
50255
+ var init_types = __esm({
50256
+ "src/types.ts"() {
50257
+ "use strict";
50258
+ }
50259
+ });
50260
+
49957
50261
  // src/account-config.ts
49958
50262
  function listAccountIds(cfg) {
49959
50263
  const av = cfg?.channels?.agentvault;
@@ -50347,6 +50651,88 @@ async function sendDecisionToOwner(request, options) {
50347
50651
  return { ok: false, error: friendlyError(err) };
50348
50652
  }
50349
50653
  }
50654
+ async function sendToRoom(roomId, text, options) {
50655
+ if (typeof text !== "string" || text.trim().length === 0) {
50656
+ return { ok: false, error: "Message text must be a non-empty string" };
50657
+ }
50658
+ if (!roomId) {
50659
+ return { ok: false, error: "Room ID is required" };
50660
+ }
50661
+ requestHeartbeatNow({ reason: "proactive-room-send" }).catch(() => {
50662
+ });
50663
+ try {
50664
+ const base = resolveBaseUrl(options);
50665
+ const sendPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/send" : "/send";
50666
+ const res = await fetch(`${base}${sendPath}`, {
50667
+ method: "POST",
50668
+ headers: { "Content-Type": "application/json" },
50669
+ body: JSON.stringify({ text, room_id: roomId }),
50670
+ signal: options?.signal
50671
+ });
50672
+ if (!res.ok) {
50673
+ const body = await res.text().catch(() => "");
50674
+ return { ok: false, error: `HTTP ${res.status}${body ? `: ${body}` : ""}` };
50675
+ }
50676
+ const data = await res.json();
50677
+ return { ok: data.ok ?? true };
50678
+ } catch (err) {
50679
+ return { ok: false, error: friendlyError(err) };
50680
+ }
50681
+ }
50682
+ async function sendToTarget(target, text, options) {
50683
+ if (typeof text !== "string" || text.trim().length === 0) {
50684
+ return { ok: false, error: "Message text must be a non-empty string" };
50685
+ }
50686
+ requestHeartbeatNow({ reason: "proactive-target-send" }).catch(() => {
50687
+ });
50688
+ try {
50689
+ const base = resolveBaseUrl(options);
50690
+ const sendPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/send" : "/send";
50691
+ const body = { text };
50692
+ if (target.startsWith("room:")) {
50693
+ body.room_id = target.slice(5);
50694
+ } else if (target.startsWith("a2a:")) {
50695
+ body.hub_address = target.slice(4);
50696
+ } else if (target === "context") {
50697
+ body.target = "context";
50698
+ }
50699
+ const res = await fetch(`${base}${sendPath}`, {
50700
+ method: "POST",
50701
+ headers: { "Content-Type": "application/json" },
50702
+ body: JSON.stringify(body),
50703
+ signal: options?.signal
50704
+ });
50705
+ if (!res.ok) {
50706
+ const respBody = await res.text().catch(() => "");
50707
+ return { ok: false, error: `HTTP ${res.status}${respBody ? `: ${respBody}` : ""}` };
50708
+ }
50709
+ const data = await res.json();
50710
+ return {
50711
+ ok: data.ok ?? true,
50712
+ destination: data.destination
50713
+ };
50714
+ } catch (err) {
50715
+ return { ok: false, error: friendlyError(err) };
50716
+ }
50717
+ }
50718
+ async function listTargets(options) {
50719
+ try {
50720
+ const base = resolveBaseUrl(options);
50721
+ const targetsPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/targets" : "/targets";
50722
+ const res = await fetch(`${base}${targetsPath}`, { signal: options?.signal });
50723
+ if (!res.ok) {
50724
+ return { ok: false, error: `HTTP ${res.status}` };
50725
+ }
50726
+ const data = await res.json();
50727
+ return {
50728
+ ok: true,
50729
+ targets: data.targets,
50730
+ context: data.context
50731
+ };
50732
+ } catch (err) {
50733
+ return { ok: false, error: friendlyError(err) };
50734
+ }
50735
+ }
50350
50736
  async function checkGateway(options) {
50351
50737
  try {
50352
50738
  const base = resolveBaseUrl(options);
@@ -50392,6 +50778,7 @@ var init_openclaw_entry = __esm({
50392
50778
  init_fetch_interceptor();
50393
50779
  init_http_handlers();
50394
50780
  init_openclaw_compat();
50781
+ init_types();
50395
50782
  isUsingManagedRoutes = false;
50396
50783
  }
50397
50784
  });
@@ -51074,7 +51461,7 @@ function createZodEnum(values, params) {
51074
51461
  });
51075
51462
  }
51076
51463
  var ParseInputLazyPath, handleResult, ZodType, cuidRegex, cuid2Regex, ulidRegex, uuidRegex, nanoidRegex, jwtRegex, durationRegex, emailRegex, _emojiRegex, emojiRegex, ipv4Regex, ipv4CidrRegex, ipv6Regex, ipv6CidrRegex, base64Regex, base64urlRegex, dateRegexSource, dateRegex, ZodString, ZodNumber, ZodBigInt, ZodBoolean, ZodDate, ZodSymbol, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodVoid, ZodArray, ZodObject, ZodUnion, getDiscriminator, ZodDiscriminatedUnion, ZodIntersection, ZodTuple, ZodRecord, ZodMap, ZodSet, ZodFunction, ZodLazy, ZodLiteral, ZodEnum, ZodNativeEnum, ZodPromise, ZodEffects, ZodOptional, ZodNullable, ZodDefault, ZodCatch, ZodNaN, ZodBranded, ZodPipeline, ZodReadonly, late, ZodFirstPartyTypeKind, stringType, numberType, nanType, bigIntType, booleanType, dateType, symbolType, undefinedType, nullType, anyType, unknownType, neverType, voidType, arrayType, objectType, strictObjectType, unionType, discriminatedUnionType, intersectionType, tupleType, recordType, mapType, setType, functionType, lazyType, literalType, enumType, nativeEnumType, promiseType, effectsType, optionalType, nullableType, preprocessType, pipelineType;
51077
- var init_types = __esm({
51464
+ var init_types2 = __esm({
51078
51465
  "../../node_modules/zod/v3/types.js"() {
51079
51466
  init_ZodError();
51080
51467
  init_errors();
@@ -54326,7 +54713,7 @@ var init_external = __esm({
54326
54713
  init_parseUtil();
54327
54714
  init_typeAliases();
54328
54715
  init_util();
54329
- init_types();
54716
+ init_types2();
54330
54717
  init_ZodError();
54331
54718
  }
54332
54719
  });
@@ -62098,7 +62485,7 @@ function assertCompleteRequestResourceTemplate(request) {
62098
62485
  void request;
62099
62486
  }
62100
62487
  var LATEST_PROTOCOL_VERSION, DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, RELATED_TASK_META_KEY, JSONRPC_VERSION, AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskCreationParamsSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, isTaskAugmentedRequestParams, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, isJSONRPCRequest, JSONRPCNotificationSchema, isJSONRPCNotification, JSONRPCResultResponseSchema, isJSONRPCResultResponse, ErrorCode, JSONRPCErrorResponseSchema, isJSONRPCErrorResponse, JSONRPCMessageSchema, JSONRPCResponseSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, isInitializeRequest, ServerCapabilitiesSchema, InitializeResultSchema, InitializedNotificationSchema, PingRequestSchema, ProgressSchema, ProgressNotificationParamsSchema, ProgressNotificationSchema, PaginatedRequestParamsSchema, PaginatedRequestSchema, PaginatedResultSchema, TaskStatusSchema, TaskSchema, CreateTaskResultSchema, TaskStatusNotificationParamsSchema, TaskStatusNotificationSchema, GetTaskRequestSchema, GetTaskResultSchema, GetTaskPayloadRequestSchema, GetTaskPayloadResultSchema, ListTasksRequestSchema, ListTasksResultSchema, CancelTaskRequestSchema, CancelTaskResultSchema, ResourceContentsSchema, TextResourceContentsSchema, Base64Schema, BlobResourceContentsSchema, RoleSchema, AnnotationsSchema, ResourceSchema, ResourceTemplateSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ResourceRequestParamsSchema, ReadResourceRequestParamsSchema, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SubscribeRequestParamsSchema, SubscribeRequestSchema, UnsubscribeRequestParamsSchema, UnsubscribeRequestSchema, ResourceUpdatedNotificationParamsSchema, ResourceUpdatedNotificationSchema, PromptArgumentSchema, PromptSchema, ListPromptsRequestSchema, ListPromptsResultSchema, GetPromptRequestParamsSchema, GetPromptRequestSchema, TextContentSchema, ImageContentSchema, AudioContentSchema, ToolUseContentSchema, EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema, PromptMessageSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolAnnotationsSchema, ToolExecutionSchema, ToolSchema, ListToolsRequestSchema, ListToolsResultSchema, CallToolResultSchema, CompatibilityCallToolResultSchema, CallToolRequestParamsSchema, CallToolRequestSchema, ToolListChangedNotificationSchema, ListChangedOptionsBaseSchema, LoggingLevelSchema, SetLevelRequestParamsSchema, SetLevelRequestSchema, LoggingMessageNotificationParamsSchema, LoggingMessageNotificationSchema, ModelHintSchema, ModelPreferencesSchema, ToolChoiceSchema, ToolResultContentSchema, SamplingContentSchema, SamplingMessageContentBlockSchema, SamplingMessageSchema, CreateMessageRequestParamsSchema, CreateMessageRequestSchema, CreateMessageResultSchema, CreateMessageResultWithToolsSchema, BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema, LegacyTitledEnumSchemaSchema, SingleSelectEnumSchemaSchema, UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema, MultiSelectEnumSchemaSchema, EnumSchemaSchema, PrimitiveSchemaDefinitionSchema, ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema, ElicitRequestParamsSchema, ElicitRequestSchema, ElicitationCompleteNotificationParamsSchema, ElicitationCompleteNotificationSchema, ElicitResultSchema, ResourceTemplateReferenceSchema, PromptReferenceSchema, CompleteRequestParamsSchema, CompleteRequestSchema, CompleteResultSchema, RootSchema, ListRootsRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, ClientRequestSchema, ClientNotificationSchema, ClientResultSchema, ServerRequestSchema, ServerNotificationSchema, ServerResultSchema, McpError, UrlElicitationRequiredError;
62101
- var init_types2 = __esm({
62488
+ var init_types3 = __esm({
62102
62489
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/types.js"() {
62103
62490
  init_v4();
62104
62491
  LATEST_PROTOCOL_VERSION = "2025-11-25";
@@ -65264,7 +65651,7 @@ var DEFAULT_REQUEST_TIMEOUT_MSEC, Protocol;
65264
65651
  var init_protocol = __esm({
65265
65652
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js"() {
65266
65653
  init_zod_compat();
65267
- init_types2();
65654
+ init_types3();
65268
65655
  init_interfaces();
65269
65656
  init_zod_json_schema_compat();
65270
65657
  DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
@@ -73160,7 +73547,7 @@ var Server;
73160
73547
  var init_server2 = __esm({
73161
73548
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js"() {
73162
73549
  init_protocol();
73163
- init_types2();
73550
+ init_types3();
73164
73551
  init_ajv_provider();
73165
73552
  init_zod_compat();
73166
73553
  init_server();
@@ -73730,7 +74117,7 @@ var init_mcp = __esm({
73730
74117
  init_server2();
73731
74118
  init_zod_compat();
73732
74119
  init_zod_json_schema_compat();
73733
- init_types2();
74120
+ init_types3();
73734
74121
  init_completable();
73735
74122
  init_uriTemplate();
73736
74123
  init_toolNameValidation();
@@ -75002,7 +75389,7 @@ var init_dist2 = __esm({
75002
75389
  var WebStandardStreamableHTTPServerTransport;
75003
75390
  var init_webStandardStreamableHttp = __esm({
75004
75391
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js"() {
75005
- init_types2();
75392
+ init_types3();
75006
75393
  WebStandardStreamableHTTPServerTransport = class {
75007
75394
  constructor(options = {}) {
75008
75395
  this._started = false;
@@ -76302,6 +76689,7 @@ var VERSION;
76302
76689
  var init_index = __esm({
76303
76690
  async "src/index.ts"() {
76304
76691
  await init_channel();
76692
+ init_types();
76305
76693
  init_account_config();
76306
76694
  await init_openclaw_plugin();
76307
76695
  init_gateway_send();
@@ -76331,20 +76719,25 @@ export {
76331
76719
  handleDecisionRequest,
76332
76720
  handleSendRequest,
76333
76721
  handleStatusRequest,
76722
+ handleTargetsRequest,
76334
76723
  invokeSkill,
76335
76724
  isUsingManagedRoutes,
76336
76725
  listAccountIds,
76726
+ listTargets,
76337
76727
  loadSkillsFromApi,
76338
76728
  loadSkillsFromDirectory,
76339
76729
  mergeSkills,
76340
76730
  onAgentEvent,
76341
76731
  onSessionTranscriptUpdate,
76342
76732
  parseSkillMd,
76733
+ parseTarget,
76343
76734
  reportSkillInvocation,
76344
76735
  requestHeartbeatNow,
76345
76736
  resolveAccount,
76346
76737
  sendDecisionToOwner,
76347
76738
  sendToOwner,
76739
+ sendToRoom,
76740
+ sendToTarget,
76348
76741
  setOcRuntime,
76349
76742
  wrapSkillExecution
76350
76743
  };