@agentvault/agentvault 0.15.3 → 0.17.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
@@ -45996,6 +45996,37 @@ function buildEvalSpan(opts) {
45996
45996
  status: { code: 0 }
45997
45997
  };
45998
45998
  }
45999
+ function buildPolicyViolationSpan(opts) {
46000
+ const now = Date.now();
46001
+ const attributes = {
46002
+ "av.policy.rule_id": opts.ruleId,
46003
+ "av.policy.scope": opts.policyScope,
46004
+ "av.policy.action_taken": opts.actionTaken,
46005
+ "av.policy.violation_type": opts.violationType
46006
+ };
46007
+ if (opts.targetTool)
46008
+ attributes["av.policy.target_tool"] = opts.targetTool;
46009
+ if (opts.targetModel)
46010
+ attributes["av.policy.target_model"] = opts.targetModel;
46011
+ if (opts.messageType)
46012
+ attributes["av.policy.message_type"] = opts.messageType;
46013
+ applySkillName(attributes, opts.skillName);
46014
+ const isBlock = opts.actionTaken === "block";
46015
+ return {
46016
+ traceId: opts.traceId ?? generateTraceId(),
46017
+ spanId: opts.spanId ?? generateSpanId(),
46018
+ parentSpanId: opts.parentSpanId,
46019
+ name: "av.policy.evaluate",
46020
+ kind: "internal",
46021
+ startTime: now,
46022
+ endTime: now,
46023
+ attributes,
46024
+ status: isBlock ? { code: 2, message: `Policy violation: ${opts.violationType}` } : { code: 0 }
46025
+ };
46026
+ }
46027
+ function buildTraceparent(span) {
46028
+ return `00-${span.traceId}-${span.spanId}-01`;
46029
+ }
45999
46030
  var init_telemetry = __esm({
46000
46031
  "../crypto/dist/telemetry.js"() {
46001
46032
  "use strict";
@@ -46018,6 +46049,9 @@ function toOtlpAttributes(attrs) {
46018
46049
  });
46019
46050
  }
46020
46051
  function spanToOtlp(span) {
46052
+ const enrichedAttrs = { ...span.attributes };
46053
+ enrichedAttrs["w3c.traceparent"] = buildTraceparent(span);
46054
+ enrichedAttrs["w3c.tracestate"] = `av=s:${span.spanId}`;
46021
46055
  const otlp = {
46022
46056
  traceId: span.traceId,
46023
46057
  spanId: span.spanId,
@@ -46025,7 +46059,7 @@ function spanToOtlp(span) {
46025
46059
  kind: span.kind,
46026
46060
  startTimeUnixNano: String(span.startTime * 1e6),
46027
46061
  endTimeUnixNano: String(span.endTime * 1e6),
46028
- attributes: toOtlpAttributes(span.attributes)
46062
+ attributes: toOtlpAttributes(enrichedAttrs)
46029
46063
  };
46030
46064
  if (span.parentSpanId !== void 0) {
46031
46065
  otlp.parentSpanId = span.parentSpanId;
@@ -46202,6 +46236,14 @@ var init_backup = __esm({
46202
46236
  }
46203
46237
  });
46204
46238
 
46239
+ // ../crypto/dist/approval.js
46240
+ var init_approval = __esm({
46241
+ async "../crypto/dist/approval.js"() {
46242
+ "use strict";
46243
+ await init_did();
46244
+ }
46245
+ });
46246
+
46205
46247
  // ../crypto/dist/index.js
46206
46248
  var init_dist = __esm({
46207
46249
  async "../crypto/dist/index.js"() {
@@ -46219,6 +46261,7 @@ var init_dist = __esm({
46219
46261
  init_telemetry();
46220
46262
  init_telemetry_reporter();
46221
46263
  await init_backup();
46264
+ await init_approval();
46222
46265
  }
46223
46266
  });
46224
46267
 
@@ -46496,7 +46539,8 @@ __export(http_handlers_exports, {
46496
46539
  handleActionRequest: () => handleActionRequest,
46497
46540
  handleDecisionRequest: () => handleDecisionRequest,
46498
46541
  handleSendRequest: () => handleSendRequest,
46499
- handleStatusRequest: () => handleStatusRequest
46542
+ handleStatusRequest: () => handleStatusRequest,
46543
+ handleTargetsRequest: () => handleTargetsRequest
46500
46544
  });
46501
46545
  async function handleSendRequest(parsed, channel) {
46502
46546
  const text = parsed.text;
@@ -46504,32 +46548,55 @@ async function handleSendRequest(parsed, channel) {
46504
46548
  return { status: 400, body: { ok: false, error: "Missing 'text' field" } };
46505
46549
  }
46506
46550
  try {
46551
+ let target;
46507
46552
  let a2aTarget = parsed.hub_address ?? parsed.a2a_address ?? parsed.a2aAddress;
46508
46553
  if (!a2aTarget && parsed.channel_id && typeof parsed.channel_id === "string") {
46509
46554
  const hubAddr = channel.resolveA2AChannelHub(parsed.channel_id);
46510
46555
  if (hubAddr) a2aTarget = hubAddr;
46511
46556
  }
46512
- const roomId = (typeof parsed.room_id === "string" ? parsed.room_id : void 0) ?? channel.lastInboundRoomId;
46513
46557
  if (a2aTarget && typeof a2aTarget === "string") {
46514
- await channel.sendToAgent(a2aTarget, text);
46515
- } else if (roomId) {
46516
- await channel.sendToRoom(roomId, text, {
46517
- messageType: parsed.message_type,
46518
- priority: parsed.priority,
46519
- metadata: parsed.metadata
46520
- });
46558
+ target = { kind: "a2a", hubAddress: a2aTarget };
46559
+ } else if (typeof parsed.room_id === "string") {
46560
+ target = { kind: "room", roomId: parsed.room_id };
46561
+ } else if (parsed.target === "context") {
46562
+ target = { kind: "context" };
46521
46563
  } else if (parsed.file_path && typeof parsed.file_path === "string") {
46522
- await channel.sendWithAttachment(text, parsed.file_path, {
46523
- topicId: parsed.topicId
46524
- });
46564
+ const receipt2 = await channel.deliver(
46565
+ { kind: "owner" },
46566
+ { type: "attachment", text, filePath: parsed.file_path },
46567
+ { topicId: parsed.topicId }
46568
+ );
46569
+ return {
46570
+ status: receipt2.ok ? 200 : 500,
46571
+ body: {
46572
+ ok: receipt2.ok,
46573
+ destination: receipt2.destination,
46574
+ ...receipt2.error ? { error: receipt2.error } : {}
46575
+ }
46576
+ };
46525
46577
  } else {
46526
- await channel.send(text, {
46527
- topicId: parsed.topicId,
46528
- messageType: parsed.message_type,
46529
- metadata: parsed.metadata
46530
- });
46578
+ target = { kind: "owner" };
46531
46579
  }
46532
- return { status: 200, body: { ok: true } };
46580
+ const receipt = await channel.deliver(
46581
+ target,
46582
+ { type: "text", text },
46583
+ {
46584
+ topicId: parsed.topicId,
46585
+ priority: parsed.priority,
46586
+ metadata: {
46587
+ ...parsed.metadata,
46588
+ ...parsed.message_type ? { message_type: parsed.message_type } : {}
46589
+ }
46590
+ }
46591
+ );
46592
+ return {
46593
+ status: receipt.ok ? 200 : 500,
46594
+ body: {
46595
+ ok: receipt.ok,
46596
+ destination: receipt.destination,
46597
+ ...receipt.error ? { error: receipt.error } : {}
46598
+ }
46599
+ };
46533
46600
  } catch (err) {
46534
46601
  return { status: 500, body: { ok: false, error: String(err) } };
46535
46602
  }
@@ -46546,12 +46613,19 @@ async function handleActionRequest(parsed, channel) {
46546
46613
  detail: parsed.detail,
46547
46614
  estimated_cost: parsed.estimated_cost
46548
46615
  };
46549
- if (parsed.room_id && typeof parsed.room_id === "string") {
46550
- await channel.sendActionConfirmationToRoom(parsed.room_id, confirmation);
46551
- } else {
46552
- await channel.sendActionConfirmation(confirmation);
46553
- }
46554
- return { status: 200, body: { ok: true } };
46616
+ const target = parsed.room_id && typeof parsed.room_id === "string" ? { kind: "room", roomId: parsed.room_id } : { kind: "owner" };
46617
+ const receipt = await channel.deliver(
46618
+ target,
46619
+ { type: "action_confirmation", confirmation }
46620
+ );
46621
+ return {
46622
+ status: receipt.ok ? 200 : 500,
46623
+ body: {
46624
+ ok: receipt.ok,
46625
+ destination: receipt.destination,
46626
+ ...receipt.error ? { error: receipt.error } : {}
46627
+ }
46628
+ };
46555
46629
  } catch (err) {
46556
46630
  return { status: 500, body: { ok: false, error: String(err) } };
46557
46631
  }
@@ -46595,6 +46669,16 @@ function handleStatusRequest(channel) {
46595
46669
  }
46596
46670
  };
46597
46671
  }
46672
+ function handleTargetsRequest(channel) {
46673
+ return {
46674
+ status: 200,
46675
+ body: {
46676
+ ok: true,
46677
+ targets: channel.listTargets(),
46678
+ context: channel.lastInboundRoomId ? { kind: "room", roomId: channel.lastInboundRoomId } : { kind: "owner" }
46679
+ }
46680
+ };
46681
+ }
46598
46682
  var init_http_handlers = __esm({
46599
46683
  "src/http-handlers.ts"() {
46600
46684
  "use strict";
@@ -47574,6 +47658,171 @@ var init_channel = __esm({
47574
47658
  metadata
47575
47659
  });
47576
47660
  }
47661
+ // --- Unified Delivery Protocol ---
47662
+ /**
47663
+ * Canonical message dispatcher. ALL outbound messages should flow through this method.
47664
+ * Routes based on explicit target — never silently falls back to a room.
47665
+ */
47666
+ async deliver(target, content, options) {
47667
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
47668
+ if (this._state === "idle" || this._state === "error") {
47669
+ return {
47670
+ ok: false,
47671
+ destination: { kind: "owner" },
47672
+ error: `Channel is in ${this._state} state`,
47673
+ timestamp: ts
47674
+ };
47675
+ }
47676
+ let resolved;
47677
+ if (target.kind === "context") {
47678
+ if (this._lastInboundRoomId) {
47679
+ resolved = { kind: "room", id: this._lastInboundRoomId };
47680
+ console.log(`[deliver] target=context\u2192room:${this._lastInboundRoomId.slice(0, 8)}...`);
47681
+ } else {
47682
+ resolved = { kind: "owner" };
47683
+ console.log(`[deliver] target=context\u2192owner`);
47684
+ }
47685
+ } else if (target.kind === "owner") {
47686
+ resolved = { kind: "owner" };
47687
+ } else if (target.kind === "room") {
47688
+ if (!this._persisted?.rooms?.[target.roomId]) {
47689
+ const err = `Room ${target.roomId} not found`;
47690
+ console.log(`[deliver] target=room:${target.roomId.slice(0, 8)}... content=${content.type} result=FAIL: ${err}`);
47691
+ return { ok: false, destination: { kind: "room", id: target.roomId }, error: err, timestamp: ts };
47692
+ }
47693
+ resolved = { kind: "room", id: target.roomId };
47694
+ } else if (target.kind === "a2a") {
47695
+ const channelEntry = this._persisted?.a2aChannels ? Object.values(this._persisted.a2aChannels).find((ch) => ch.hubAddress === target.hubAddress) : void 0;
47696
+ if (!channelEntry) {
47697
+ const err = `No A2A channel found for hub address: ${target.hubAddress}`;
47698
+ console.log(`[deliver] target=a2a:${target.hubAddress} content=${content.type} result=FAIL: ${err}`);
47699
+ return { ok: false, destination: { kind: "a2a", id: target.hubAddress }, error: err, timestamp: ts };
47700
+ }
47701
+ resolved = { kind: "a2a", id: target.hubAddress };
47702
+ } else {
47703
+ return { ok: false, destination: { kind: "owner" }, error: "Unknown target kind", timestamp: ts };
47704
+ }
47705
+ try {
47706
+ let decisionId;
47707
+ if (content.type === "text") {
47708
+ if (resolved.kind === "room") {
47709
+ await this.sendToRoom(resolved.id, content.text, {
47710
+ messageType: options?.metadata?.message_type,
47711
+ priority: options?.priority,
47712
+ metadata: options?.metadata
47713
+ });
47714
+ } else if (resolved.kind === "a2a") {
47715
+ await this.sendToAgent(resolved.id, content.text, {
47716
+ parentSpanId: options?.parentSpanId
47717
+ });
47718
+ } else {
47719
+ await this.send(content.text, {
47720
+ conversationId: options?.conversationId,
47721
+ topicId: options?.topicId,
47722
+ messageType: options?.metadata?.message_type,
47723
+ priority: options?.priority,
47724
+ metadata: options?.metadata
47725
+ });
47726
+ }
47727
+ } else if (content.type === "decision_request") {
47728
+ if (resolved.kind !== "owner") {
47729
+ const err = "Decision requests can only be sent to owner";
47730
+ console.log(`[deliver] target=${resolved.kind}:${resolved.id} content=decision_request result=FAIL: ${err}`);
47731
+ return { ok: false, destination: resolved, error: err, timestamp: ts };
47732
+ }
47733
+ decisionId = await this.sendDecisionRequest(content.request);
47734
+ } else if (content.type === "status_alert") {
47735
+ if (resolved.kind === "room") {
47736
+ const envelope = {
47737
+ title: content.alert.title,
47738
+ message: content.alert.message,
47739
+ severity: content.alert.severity,
47740
+ timestamp: ts
47741
+ };
47742
+ if (content.alert.detail !== void 0) envelope.detail = content.alert.detail;
47743
+ if (content.alert.detailFormat !== void 0) envelope.detail_format = content.alert.detailFormat;
47744
+ if (content.alert.category !== void 0) envelope.category = content.alert.category;
47745
+ await this.sendToRoom(resolved.id, JSON.stringify(envelope), {
47746
+ messageType: "status_alert",
47747
+ priority: content.alert.severity === "error" || content.alert.severity === "critical" ? "high" : "normal",
47748
+ metadata: { severity: content.alert.severity }
47749
+ });
47750
+ } else if (resolved.kind === "owner") {
47751
+ await this.sendStatusAlert(content.alert);
47752
+ } else {
47753
+ return { ok: false, destination: resolved, error: "Status alerts cannot be sent to A2A targets", timestamp: ts };
47754
+ }
47755
+ } else if (content.type === "action_confirmation") {
47756
+ if (resolved.kind === "room") {
47757
+ await this.sendActionConfirmationToRoom(resolved.id, content.confirmation);
47758
+ } else if (resolved.kind === "owner") {
47759
+ await this.sendActionConfirmation(content.confirmation);
47760
+ } else {
47761
+ return { ok: false, destination: resolved, error: "Action confirmations cannot be sent to A2A targets", timestamp: ts };
47762
+ }
47763
+ } else if (content.type === "artifact") {
47764
+ if (resolved.kind !== "owner") {
47765
+ return { ok: false, destination: resolved, error: "Artifacts can only be sent to owner", timestamp: ts };
47766
+ }
47767
+ await this.sendArtifact(content.artifact);
47768
+ } else if (content.type === "attachment") {
47769
+ if (resolved.kind !== "owner") {
47770
+ return { ok: false, destination: resolved, error: "Attachments can only be sent to owner", timestamp: ts };
47771
+ }
47772
+ await this.sendWithAttachment(content.text, content.filePath, {
47773
+ topicId: options?.topicId
47774
+ });
47775
+ }
47776
+ const targetLabel = resolved.kind === "owner" ? "owner" : `${resolved.kind}:${resolved.id?.slice(0, 8)}...`;
47777
+ console.log(`[deliver] target=${targetLabel} content=${content.type} result=ok`);
47778
+ return {
47779
+ ok: true,
47780
+ destination: resolved,
47781
+ queued: this._state !== "ready",
47782
+ decisionId,
47783
+ timestamp: ts
47784
+ };
47785
+ } catch (err) {
47786
+ const targetLabel = resolved.kind === "owner" ? "owner" : `${resolved.kind}:${resolved.id?.slice(0, 8)}...`;
47787
+ const errMsg = err instanceof Error ? err.message : String(err);
47788
+ console.log(`[deliver] target=${targetLabel} content=${content.type} result=FAIL: ${errMsg}`);
47789
+ return { ok: false, destination: resolved, error: errMsg, timestamp: ts };
47790
+ }
47791
+ }
47792
+ /**
47793
+ * Returns all available delivery destinations with availability status.
47794
+ */
47795
+ listTargets() {
47796
+ const targets = [
47797
+ {
47798
+ kind: "owner",
47799
+ id: "owner",
47800
+ label: "Owner (direct)",
47801
+ available: this._state === "ready" && this._sessions.size > 0
47802
+ }
47803
+ ];
47804
+ if (this._persisted?.rooms) {
47805
+ for (const room of Object.values(this._persisted.rooms)) {
47806
+ targets.push({
47807
+ kind: "room",
47808
+ id: room.roomId,
47809
+ label: room.name || `Room ${room.roomId.slice(0, 8)}`,
47810
+ available: this._state === "ready" && room.conversationIds.length > 0
47811
+ });
47812
+ }
47813
+ }
47814
+ if (this._persisted?.a2aChannels) {
47815
+ for (const ch of Object.values(this._persisted.a2aChannels)) {
47816
+ targets.push({
47817
+ kind: "a2a",
47818
+ id: ch.hubAddress,
47819
+ label: `A2A: ${ch.hubAddress}`,
47820
+ available: this._state === "ready" && !!ch.session?.ratchetState
47821
+ });
47822
+ }
47823
+ }
47824
+ return targets;
47825
+ }
47577
47826
  _sendHeartbeat() {
47578
47827
  if (this._state !== "ready" || !this._heartbeatCallback) return;
47579
47828
  const status = this._heartbeatCallback();
@@ -47692,9 +47941,13 @@ var init_channel = __esm({
47692
47941
  const result = handlers.handleStatusRequest(this);
47693
47942
  res.writeHead(result.status, { "Content-Type": "application/json" });
47694
47943
  res.end(JSON.stringify(result.body));
47944
+ } else if (req.method === "GET" && req.url === "/targets") {
47945
+ const result = handlers.handleTargetsRequest(this);
47946
+ res.writeHead(result.status, { "Content-Type": "application/json" });
47947
+ res.end(JSON.stringify(result.body));
47695
47948
  } else {
47696
47949
  res.writeHead(404, { "Content-Type": "application/json" });
47697
- res.end(JSON.stringify({ ok: false, error: "Not found. Use POST /send, POST /decision, POST /action, or GET /status" }));
47950
+ res.end(JSON.stringify({ ok: false, error: "Not found. Use POST /send, POST /decision, POST /action, GET /status, or GET /targets" }));
47698
47951
  }
47699
47952
  });
47700
47953
  this._httpServer.listen(port, "127.0.0.1", () => {
@@ -48303,10 +48556,11 @@ var init_channel = __esm({
48303
48556
  }
48304
48557
  if (data.event === "hub_identity_sync") {
48305
48558
  if (this._persisted && data.data?.hub_id) {
48306
- const changed = this._persisted.hubId !== data.data.hub_id;
48559
+ const changed = this._persisted.hubId !== data.data.hub_id || this._persisted.agentRole !== (data.data.agent_role ?? "peer");
48307
48560
  this._persisted.hubAddress = data.data.hub_address;
48308
48561
  this._persisted.hubId = data.data.hub_id;
48309
48562
  this._persisted.agentHubId = data.data.hub_id;
48563
+ this._persisted.agentRole = data.data.agent_role ?? "peer";
48310
48564
  if (changed) this._persistState();
48311
48565
  if (!this._telemetryReporter && this._persisted.deviceJwt && this._persisted.hubId) {
48312
48566
  this._telemetryReporter = new TelemetryReporter({
@@ -48328,6 +48582,14 @@ var init_channel = __esm({
48328
48582
  }
48329
48583
  this.emit("hub_identity_assigned", data.data);
48330
48584
  }
48585
+ if (data.event === "hub_identity_role_changed") {
48586
+ if (this._persisted && data.data?.agent_role) {
48587
+ this._persisted.agentRole = data.data.agent_role;
48588
+ this._persistState();
48589
+ console.log(`[SecureChannel] Agent role changed to: ${data.data.agent_role}`);
48590
+ }
48591
+ this.emit("hub_identity_role_changed", data.data);
48592
+ }
48331
48593
  if (data.event === "hub_identity_removed") {
48332
48594
  if (this._persisted) {
48333
48595
  delete this._persisted.hubAddress;
@@ -48994,6 +49256,9 @@ ${messageText}`;
48994
49256
  _resolveWorkspaceDir() {
48995
49257
  const homedir = process.env.HOME ?? process.env.USERPROFILE ?? "/tmp";
48996
49258
  const agentName = this.config.agentName;
49259
+ if (this._persisted?.agentRole === "lead") {
49260
+ return join3(homedir, ".openclaw", "workspace");
49261
+ }
48997
49262
  try {
48998
49263
  const configPath = join3(homedir, ".openclaw", "openclaw.json");
48999
49264
  const raw = __require("node:fs").readFileSync(configPath, "utf-8");
@@ -50015,6 +50280,39 @@ ${messageText}`;
50015
50280
  }
50016
50281
  });
50017
50282
 
50283
+ // src/types.ts
50284
+ function parseTarget(raw) {
50285
+ let target = raw;
50286
+ if (target.startsWith("agentvault:")) {
50287
+ target = target.slice("agentvault:".length);
50288
+ }
50289
+ if (target.startsWith("agent:")) {
50290
+ target = "a2a:" + target.slice("agent:".length);
50291
+ }
50292
+ if (target === "owner" || target === "default") {
50293
+ return { kind: "owner" };
50294
+ }
50295
+ if (target === "context") {
50296
+ return { kind: "context" };
50297
+ }
50298
+ if (target.startsWith("room:")) {
50299
+ const roomId = target.slice("room:".length);
50300
+ if (!roomId) throw new Error(`Invalid room target: "${raw}" \u2014 missing room ID`);
50301
+ return { kind: "room", roomId };
50302
+ }
50303
+ if (target.startsWith("a2a:")) {
50304
+ const hubAddress = target.slice("a2a:".length);
50305
+ if (!hubAddress) throw new Error(`Invalid A2A target: "${raw}" \u2014 missing hub address`);
50306
+ return { kind: "a2a", hubAddress };
50307
+ }
50308
+ throw new Error(`Unrecognized delivery target: "${raw}". Use "owner", "room:<id>", "a2a:<addr>", or "context".`);
50309
+ }
50310
+ var init_types = __esm({
50311
+ "src/types.ts"() {
50312
+ "use strict";
50313
+ }
50314
+ });
50315
+
50018
50316
  // src/account-config.ts
50019
50317
  function listAccountIds(cfg) {
50020
50318
  const av = cfg?.channels?.agentvault;
@@ -50408,6 +50706,88 @@ async function sendDecisionToOwner(request, options) {
50408
50706
  return { ok: false, error: friendlyError(err) };
50409
50707
  }
50410
50708
  }
50709
+ async function sendToRoom(roomId, text, options) {
50710
+ if (typeof text !== "string" || text.trim().length === 0) {
50711
+ return { ok: false, error: "Message text must be a non-empty string" };
50712
+ }
50713
+ if (!roomId) {
50714
+ return { ok: false, error: "Room ID is required" };
50715
+ }
50716
+ requestHeartbeatNow({ reason: "proactive-room-send" }).catch(() => {
50717
+ });
50718
+ try {
50719
+ const base = resolveBaseUrl(options);
50720
+ const sendPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/send" : "/send";
50721
+ const res = await fetch(`${base}${sendPath}`, {
50722
+ method: "POST",
50723
+ headers: { "Content-Type": "application/json" },
50724
+ body: JSON.stringify({ text, room_id: roomId }),
50725
+ signal: options?.signal
50726
+ });
50727
+ if (!res.ok) {
50728
+ const body = await res.text().catch(() => "");
50729
+ return { ok: false, error: `HTTP ${res.status}${body ? `: ${body}` : ""}` };
50730
+ }
50731
+ const data = await res.json();
50732
+ return { ok: data.ok ?? true };
50733
+ } catch (err) {
50734
+ return { ok: false, error: friendlyError(err) };
50735
+ }
50736
+ }
50737
+ async function sendToTarget(target, text, options) {
50738
+ if (typeof text !== "string" || text.trim().length === 0) {
50739
+ return { ok: false, error: "Message text must be a non-empty string" };
50740
+ }
50741
+ requestHeartbeatNow({ reason: "proactive-target-send" }).catch(() => {
50742
+ });
50743
+ try {
50744
+ const base = resolveBaseUrl(options);
50745
+ const sendPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/send" : "/send";
50746
+ const body = { text };
50747
+ if (target.startsWith("room:")) {
50748
+ body.room_id = target.slice(5);
50749
+ } else if (target.startsWith("a2a:")) {
50750
+ body.hub_address = target.slice(4);
50751
+ } else if (target === "context") {
50752
+ body.target = "context";
50753
+ }
50754
+ const res = await fetch(`${base}${sendPath}`, {
50755
+ method: "POST",
50756
+ headers: { "Content-Type": "application/json" },
50757
+ body: JSON.stringify(body),
50758
+ signal: options?.signal
50759
+ });
50760
+ if (!res.ok) {
50761
+ const respBody = await res.text().catch(() => "");
50762
+ return { ok: false, error: `HTTP ${res.status}${respBody ? `: ${respBody}` : ""}` };
50763
+ }
50764
+ const data = await res.json();
50765
+ return {
50766
+ ok: data.ok ?? true,
50767
+ destination: data.destination
50768
+ };
50769
+ } catch (err) {
50770
+ return { ok: false, error: friendlyError(err) };
50771
+ }
50772
+ }
50773
+ async function listTargets(options) {
50774
+ try {
50775
+ const base = resolveBaseUrl(options);
50776
+ const targetsPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/targets" : "/targets";
50777
+ const res = await fetch(`${base}${targetsPath}`, { signal: options?.signal });
50778
+ if (!res.ok) {
50779
+ return { ok: false, error: `HTTP ${res.status}` };
50780
+ }
50781
+ const data = await res.json();
50782
+ return {
50783
+ ok: true,
50784
+ targets: data.targets,
50785
+ context: data.context
50786
+ };
50787
+ } catch (err) {
50788
+ return { ok: false, error: friendlyError(err) };
50789
+ }
50790
+ }
50411
50791
  async function checkGateway(options) {
50412
50792
  try {
50413
50793
  const base = resolveBaseUrl(options);
@@ -50453,6 +50833,7 @@ var init_openclaw_entry = __esm({
50453
50833
  init_fetch_interceptor();
50454
50834
  init_http_handlers();
50455
50835
  init_openclaw_compat();
50836
+ init_types();
50456
50837
  isUsingManagedRoutes = false;
50457
50838
  }
50458
50839
  });
@@ -51135,7 +51516,7 @@ function createZodEnum(values, params) {
51135
51516
  });
51136
51517
  }
51137
51518
  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;
51138
- var init_types = __esm({
51519
+ var init_types2 = __esm({
51139
51520
  "../../node_modules/zod/v3/types.js"() {
51140
51521
  init_ZodError();
51141
51522
  init_errors();
@@ -54387,7 +54768,7 @@ var init_external = __esm({
54387
54768
  init_parseUtil();
54388
54769
  init_typeAliases();
54389
54770
  init_util();
54390
- init_types();
54771
+ init_types2();
54391
54772
  init_ZodError();
54392
54773
  }
54393
54774
  });
@@ -62159,7 +62540,7 @@ function assertCompleteRequestResourceTemplate(request) {
62159
62540
  void request;
62160
62541
  }
62161
62542
  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;
62162
- var init_types2 = __esm({
62543
+ var init_types3 = __esm({
62163
62544
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/types.js"() {
62164
62545
  init_v4();
62165
62546
  LATEST_PROTOCOL_VERSION = "2025-11-25";
@@ -65325,7 +65706,7 @@ var DEFAULT_REQUEST_TIMEOUT_MSEC, Protocol;
65325
65706
  var init_protocol = __esm({
65326
65707
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js"() {
65327
65708
  init_zod_compat();
65328
- init_types2();
65709
+ init_types3();
65329
65710
  init_interfaces();
65330
65711
  init_zod_json_schema_compat();
65331
65712
  DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
@@ -73221,7 +73602,7 @@ var Server;
73221
73602
  var init_server2 = __esm({
73222
73603
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js"() {
73223
73604
  init_protocol();
73224
- init_types2();
73605
+ init_types3();
73225
73606
  init_ajv_provider();
73226
73607
  init_zod_compat();
73227
73608
  init_server();
@@ -73791,7 +74172,7 @@ var init_mcp = __esm({
73791
74172
  init_server2();
73792
74173
  init_zod_compat();
73793
74174
  init_zod_json_schema_compat();
73794
- init_types2();
74175
+ init_types3();
73795
74176
  init_completable();
73796
74177
  init_uriTemplate();
73797
74178
  init_toolNameValidation();
@@ -75063,7 +75444,7 @@ var init_dist2 = __esm({
75063
75444
  var WebStandardStreamableHTTPServerTransport;
75064
75445
  var init_webStandardStreamableHttp = __esm({
75065
75446
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js"() {
75066
- init_types2();
75447
+ init_types3();
75067
75448
  WebStandardStreamableHTTPServerTransport = class {
75068
75449
  constructor(options = {}) {
75069
75450
  this._started = false;
@@ -75806,7 +76187,13 @@ var init_mcp_server2 = __esm({
75806
76187
  tags: s2.tags,
75807
76188
  sla: s2.slaDefinition,
75808
76189
  hasSchema: !!s2.inputSchema,
75809
- hasInstructions: !!s2.instructions
76190
+ hasInstructions: !!s2.instructions,
76191
+ certificationTier: s2.certificationTier,
76192
+ modelRouting: s2.modelRouting,
76193
+ allowedModels: s2.allowedModels,
76194
+ hasToolPolicy: !!(s2.toolsAllowed || s2.toolsDenied),
76195
+ hasOutputSchema: !!s2.outputSchema,
76196
+ requiredPolicies: s2.requiredPolicies
75810
76197
  }));
75811
76198
  return {
75812
76199
  contents: [{
@@ -76002,7 +76389,7 @@ function parseSkillMd(content) {
76002
76389
  if (!frontmatter.name) return null;
76003
76390
  const instructionLines = lines.slice(endIdx + 1);
76004
76391
  const instructions = instructionLines.join("\n").trim();
76005
- return {
76392
+ const skill = {
76006
76393
  name: frontmatter.name,
76007
76394
  version: frontmatter.version,
76008
76395
  description: frontmatter.description,
@@ -76011,82 +76398,76 @@ function parseSkillMd(content) {
76011
76398
  slaDefinition: frontmatter.sla,
76012
76399
  instructions: instructions || void 0
76013
76400
  };
76401
+ if (frontmatter.agentVault) {
76402
+ const av = frontmatter.agentVault;
76403
+ if (av.certification) skill.certificationTier = av.certification;
76404
+ if (av.runtime?.capabilities) skill.toolsAllowed = av.runtime.capabilities;
76405
+ if (av.runtime?.forbidden) skill.toolsDenied = av.runtime.forbidden;
76406
+ if (av.runtime?.output_schema) skill.outputSchema = av.runtime.output_schema;
76407
+ if (av.model?.routing) skill.modelRouting = av.model.routing;
76408
+ if (av.model?.allowed) skill.allowedModels = av.model.allowed;
76409
+ if (av.model?.default) skill.defaultModel = av.model.default;
76410
+ if (av.integrity) skill.integrity = av.integrity;
76411
+ if (av.requiredPolicies) skill.requiredPolicies = av.requiredPolicies;
76412
+ }
76413
+ return skill;
76014
76414
  }
76015
76415
  function parseSimpleYaml(yaml) {
76016
76416
  const result = {};
76017
76417
  const lines = yaml.split("\n");
76018
- let currentKey = "";
76019
- let currentIndent = 0;
76020
- let nestedObj = null;
76418
+ const stack = [];
76419
+ let currentObj = result;
76420
+ function parseValue(raw) {
76421
+ const value = raw.replace(/^["']|["']$/g, "");
76422
+ const num = Number(value);
76423
+ if (!isNaN(num) && value !== "") return num;
76424
+ if (value === "true") return true;
76425
+ if (value === "false") return false;
76426
+ return value;
76427
+ }
76021
76428
  for (const line of lines) {
76022
76429
  const trimmed = line.trim();
76023
76430
  if (!trimmed || trimmed.startsWith("#")) continue;
76024
76431
  const indent = line.length - line.trimStart().length;
76025
- const inlineArrayMatch = trimmed.match(/^(\w[\w-]*)\s*:\s*\[(.+)\]$/);
76432
+ while (stack.length > 0 && indent <= stack[stack.length - 1].indent) {
76433
+ const popped = stack.pop();
76434
+ currentObj = stack.length > 0 ? stack[stack.length - 1].obj : result;
76435
+ currentObj[popped.key] = popped.obj;
76436
+ }
76437
+ const inlineArrayMatch = trimmed.match(/^(\w[\w_-]*)\s*:\s*\[(.+)\]$/);
76026
76438
  if (inlineArrayMatch) {
76027
76439
  const key = inlineArrayMatch[1];
76028
76440
  const values = inlineArrayMatch[2].split(",").map((v2) => v2.trim().replace(/^["']|["']$/g, ""));
76029
- if (nestedObj && indent > currentIndent) {
76030
- nestedObj[key] = values;
76441
+ if (stack.length > 0) {
76442
+ stack[stack.length - 1].obj[key] = values;
76031
76443
  } else {
76032
- if (nestedObj && currentKey) {
76033
- result[currentKey] = nestedObj;
76034
- nestedObj = null;
76035
- }
76036
- result[key] = values;
76444
+ currentObj[key] = values;
76037
76445
  }
76038
76446
  continue;
76039
76447
  }
76040
- const kvMatch = trimmed.match(/^(\w[\w-]*)\s*:\s*(.+)$/);
76041
- if (kvMatch && indent === 0) {
76042
- if (nestedObj && currentKey) {
76043
- result[currentKey] = nestedObj;
76044
- nestedObj = null;
76045
- }
76448
+ const kvMatch = trimmed.match(/^(\w[\w_-]*)\s*:\s*(.+)$/);
76449
+ if (kvMatch) {
76046
76450
  const key = kvMatch[1];
76047
- const value = kvMatch[2].replace(/^["']|["']$/g, "");
76048
- const num = Number(value);
76049
- if (!isNaN(num) && value !== "") {
76050
- result[key] = num;
76051
- } else if (value === "true") {
76052
- result[key] = true;
76053
- } else if (value === "false") {
76054
- result[key] = false;
76451
+ const val = parseValue(kvMatch[2]);
76452
+ if (stack.length > 0) {
76453
+ stack[stack.length - 1].obj[key] = val;
76055
76454
  } else {
76056
- result[key] = value;
76455
+ currentObj[key] = val;
76057
76456
  }
76058
76457
  continue;
76059
76458
  }
76060
- const nestedMatch = trimmed.match(/^(\w[\w-]*)\s*:$/);
76061
- if (nestedMatch && indent === 0) {
76062
- if (nestedObj && currentKey) {
76063
- result[currentKey] = nestedObj;
76064
- }
76065
- currentKey = nestedMatch[1];
76066
- currentIndent = indent;
76067
- nestedObj = {};
76459
+ const nestedMatch = trimmed.match(/^(\w[\w_-]*)\s*:$/);
76460
+ if (nestedMatch) {
76461
+ const key = nestedMatch[1];
76462
+ const newObj = {};
76463
+ stack.push({ key, obj: newObj, indent });
76068
76464
  continue;
76069
76465
  }
76070
- if (nestedObj && indent > 0) {
76071
- const nestedKv = trimmed.match(/^(\w[\w-]*)\s*:\s*(.+)$/);
76072
- if (nestedKv) {
76073
- const key = nestedKv[1];
76074
- const value = nestedKv[2].replace(/^["']|["']$/g, "");
76075
- const num = Number(value);
76076
- if (!isNaN(num) && value !== "") {
76077
- nestedObj[key] = num;
76078
- } else if (value === "true") {
76079
- nestedObj[key] = true;
76080
- } else if (value === "false") {
76081
- nestedObj[key] = false;
76082
- } else {
76083
- nestedObj[key] = value;
76084
- }
76085
- }
76086
- }
76087
76466
  }
76088
- if (nestedObj && currentKey) {
76089
- result[currentKey] = nestedObj;
76467
+ while (stack.length > 0) {
76468
+ const popped = stack.pop();
76469
+ const parent = stack.length > 0 ? stack[stack.length - 1].obj : result;
76470
+ parent[popped.key] = popped.obj;
76090
76471
  }
76091
76472
  return result;
76092
76473
  }
@@ -76358,11 +76739,157 @@ var init_skill_telemetry = __esm({
76358
76739
  }
76359
76740
  });
76360
76741
 
76742
+ // src/policy-enforcer.ts
76743
+ var PolicyEnforcer;
76744
+ var init_policy_enforcer = __esm({
76745
+ async "src/policy-enforcer.ts"() {
76746
+ "use strict";
76747
+ await init_dist();
76748
+ PolicyEnforcer = class {
76749
+ skills = /* @__PURE__ */ new Map();
76750
+ metrics = {
76751
+ totalEvaluations: 0,
76752
+ totalBlocks: 0,
76753
+ totalWarnings: 0,
76754
+ bySkill: {},
76755
+ byRule: {}
76756
+ };
76757
+ spanBuffer = [];
76758
+ /**
76759
+ * Register a skill definition for policy evaluation.
76760
+ */
76761
+ registerSkill(skill) {
76762
+ this.skills.set(skill.name, skill);
76763
+ }
76764
+ /**
76765
+ * Full 5-stage policy pipeline evaluation.
76766
+ */
76767
+ evaluate(ctx) {
76768
+ this.metrics.totalEvaluations++;
76769
+ const skillMetrics = this.metrics.bySkill[ctx.skillName] ??= { evaluations: 0, blocks: 0 };
76770
+ skillMetrics.evaluations++;
76771
+ const violations = [];
76772
+ const skill = this.skills.get(ctx.skillName);
76773
+ if (skill) {
76774
+ if (ctx.toolName && skill.toolsDenied?.length) {
76775
+ if (skill.toolsDenied.includes(ctx.toolName)) {
76776
+ violations.push({
76777
+ ruleId: `deny:${ctx.skillName}:${ctx.toolName}`,
76778
+ scope: "tool",
76779
+ action: "block",
76780
+ type: "forbidden_tool",
76781
+ message: `Tool "${ctx.toolName}" is forbidden for skill "${ctx.skillName}"`
76782
+ });
76783
+ }
76784
+ }
76785
+ if (ctx.toolName && skill.toolsAllowed?.length) {
76786
+ if (!skill.toolsAllowed.includes(ctx.toolName)) {
76787
+ violations.push({
76788
+ ruleId: `allow:${ctx.skillName}:${ctx.toolName}`,
76789
+ scope: "tool",
76790
+ action: "block",
76791
+ type: "tool_not_allowed",
76792
+ message: `Tool "${ctx.toolName}" is not in the allowed list for skill "${ctx.skillName}"`
76793
+ });
76794
+ }
76795
+ }
76796
+ if (ctx.model && skill.allowedModels?.length) {
76797
+ if (!skill.allowedModels.includes(ctx.model)) {
76798
+ violations.push({
76799
+ ruleId: `model:${ctx.skillName}:${ctx.model}`,
76800
+ scope: "model",
76801
+ action: "block",
76802
+ type: "model_not_allowed",
76803
+ message: `Model "${ctx.model}" is not allowed for skill "${ctx.skillName}". Allowed: ${skill.allowedModels.join(", ")}`
76804
+ });
76805
+ }
76806
+ }
76807
+ }
76808
+ const blocked = violations.some((v2) => v2.action === "block");
76809
+ for (const v2 of violations) {
76810
+ this.metrics.byRule[v2.ruleId] = (this.metrics.byRule[v2.ruleId] ?? 0) + 1;
76811
+ if (v2.action === "block") this.metrics.totalBlocks++;
76812
+ if (v2.action === "warn") this.metrics.totalWarnings++;
76813
+ this.spanBuffer.push(
76814
+ buildPolicyViolationSpan({
76815
+ ruleId: v2.ruleId,
76816
+ policyScope: v2.scope,
76817
+ actionTaken: v2.action,
76818
+ violationType: v2.type,
76819
+ targetTool: ctx.toolName,
76820
+ targetModel: ctx.model,
76821
+ skillName: ctx.skillName
76822
+ })
76823
+ );
76824
+ }
76825
+ if (blocked) {
76826
+ skillMetrics.blocks++;
76827
+ }
76828
+ return {
76829
+ allowed: !blocked,
76830
+ violations,
76831
+ stage: "report"
76832
+ };
76833
+ }
76834
+ /**
76835
+ * Wrap an MCP tool handler with policy enforcement.
76836
+ * Returns a function that checks policy before calling the original handler.
76837
+ */
76838
+ wrapHandler(skillName, handler) {
76839
+ return async (args) => {
76840
+ const result = this.evaluate({
76841
+ skillName,
76842
+ args
76843
+ });
76844
+ if (!result.allowed) {
76845
+ return {
76846
+ blocked: true,
76847
+ violations: result.violations.map((v2) => ({
76848
+ rule: v2.ruleId,
76849
+ reason: v2.message,
76850
+ scope: v2.scope
76851
+ }))
76852
+ };
76853
+ }
76854
+ return handler(args);
76855
+ };
76856
+ }
76857
+ /**
76858
+ * Get accumulated policy metrics.
76859
+ */
76860
+ getMetrics() {
76861
+ return { ...this.metrics };
76862
+ }
76863
+ /**
76864
+ * Drain buffered telemetry spans.
76865
+ */
76866
+ drainSpans() {
76867
+ const spans = this.spanBuffer;
76868
+ this.spanBuffer = [];
76869
+ return spans;
76870
+ }
76871
+ /**
76872
+ * Reset all metrics (for testing).
76873
+ */
76874
+ resetMetrics() {
76875
+ this.metrics = {
76876
+ totalEvaluations: 0,
76877
+ totalBlocks: 0,
76878
+ totalWarnings: 0,
76879
+ bySkill: {},
76880
+ byRule: {}
76881
+ };
76882
+ }
76883
+ };
76884
+ }
76885
+ });
76886
+
76361
76887
  // src/index.ts
76362
76888
  var VERSION;
76363
76889
  var init_index = __esm({
76364
76890
  async "src/index.ts"() {
76365
76891
  await init_channel();
76892
+ init_types();
76366
76893
  init_account_config();
76367
76894
  await init_openclaw_plugin();
76368
76895
  init_gateway_send();
@@ -76374,12 +76901,14 @@ var init_index = __esm({
76374
76901
  init_skill_manifest();
76375
76902
  init_skill_invoker();
76376
76903
  await init_skill_telemetry();
76904
+ await init_policy_enforcer();
76377
76905
  VERSION = "0.14.1";
76378
76906
  }
76379
76907
  });
76380
76908
  await init_index();
76381
76909
  export {
76382
76910
  AgentVaultMcpServer,
76911
+ PolicyEnforcer,
76383
76912
  SecureChannel,
76384
76913
  VERSION,
76385
76914
  agentVaultPlugin,
@@ -76392,20 +76921,25 @@ export {
76392
76921
  handleDecisionRequest,
76393
76922
  handleSendRequest,
76394
76923
  handleStatusRequest,
76924
+ handleTargetsRequest,
76395
76925
  invokeSkill,
76396
76926
  isUsingManagedRoutes,
76397
76927
  listAccountIds,
76928
+ listTargets,
76398
76929
  loadSkillsFromApi,
76399
76930
  loadSkillsFromDirectory,
76400
76931
  mergeSkills,
76401
76932
  onAgentEvent,
76402
76933
  onSessionTranscriptUpdate,
76403
76934
  parseSkillMd,
76935
+ parseTarget,
76404
76936
  reportSkillInvocation,
76405
76937
  requestHeartbeatNow,
76406
76938
  resolveAccount,
76407
76939
  sendDecisionToOwner,
76408
76940
  sendToOwner,
76941
+ sendToRoom,
76942
+ sendToTarget,
76409
76943
  setOcRuntime,
76410
76944
  wrapSkillExecution
76411
76945
  };