@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/cli.js CHANGED
@@ -45963,6 +45963,9 @@ function buildEvalSpan(opts) {
45963
45963
  status: { code: 0 }
45964
45964
  };
45965
45965
  }
45966
+ function buildTraceparent(span) {
45967
+ return `00-${span.traceId}-${span.spanId}-01`;
45968
+ }
45966
45969
  var init_telemetry = __esm({
45967
45970
  "../crypto/dist/telemetry.js"() {
45968
45971
  "use strict";
@@ -45985,6 +45988,9 @@ function toOtlpAttributes(attrs) {
45985
45988
  });
45986
45989
  }
45987
45990
  function spanToOtlp(span) {
45991
+ const enrichedAttrs = { ...span.attributes };
45992
+ enrichedAttrs["w3c.traceparent"] = buildTraceparent(span);
45993
+ enrichedAttrs["w3c.tracestate"] = `av=s:${span.spanId}`;
45988
45994
  const otlp = {
45989
45995
  traceId: span.traceId,
45990
45996
  spanId: span.spanId,
@@ -45992,7 +45998,7 @@ function spanToOtlp(span) {
45992
45998
  kind: span.kind,
45993
45999
  startTimeUnixNano: String(span.startTime * 1e6),
45994
46000
  endTimeUnixNano: String(span.endTime * 1e6),
45995
- attributes: toOtlpAttributes(span.attributes)
46001
+ attributes: toOtlpAttributes(enrichedAttrs)
45996
46002
  };
45997
46003
  if (span.parentSpanId !== void 0) {
45998
46004
  otlp.parentSpanId = span.parentSpanId;
@@ -46169,6 +46175,14 @@ var init_backup = __esm({
46169
46175
  }
46170
46176
  });
46171
46177
 
46178
+ // ../crypto/dist/approval.js
46179
+ var init_approval = __esm({
46180
+ async "../crypto/dist/approval.js"() {
46181
+ "use strict";
46182
+ await init_did();
46183
+ }
46184
+ });
46185
+
46172
46186
  // ../crypto/dist/index.js
46173
46187
  var init_dist = __esm({
46174
46188
  async "../crypto/dist/index.js"() {
@@ -46186,6 +46200,7 @@ var init_dist = __esm({
46186
46200
  init_telemetry();
46187
46201
  init_telemetry_reporter();
46188
46202
  await init_backup();
46203
+ await init_approval();
46189
46204
  }
46190
46205
  });
46191
46206
 
@@ -46463,7 +46478,8 @@ __export(http_handlers_exports, {
46463
46478
  handleActionRequest: () => handleActionRequest,
46464
46479
  handleDecisionRequest: () => handleDecisionRequest,
46465
46480
  handleSendRequest: () => handleSendRequest,
46466
- handleStatusRequest: () => handleStatusRequest
46481
+ handleStatusRequest: () => handleStatusRequest,
46482
+ handleTargetsRequest: () => handleTargetsRequest
46467
46483
  });
46468
46484
  async function handleSendRequest(parsed, channel2) {
46469
46485
  const text = parsed.text;
@@ -46471,32 +46487,55 @@ async function handleSendRequest(parsed, channel2) {
46471
46487
  return { status: 400, body: { ok: false, error: "Missing 'text' field" } };
46472
46488
  }
46473
46489
  try {
46490
+ let target;
46474
46491
  let a2aTarget = parsed.hub_address ?? parsed.a2a_address ?? parsed.a2aAddress;
46475
46492
  if (!a2aTarget && parsed.channel_id && typeof parsed.channel_id === "string") {
46476
46493
  const hubAddr = channel2.resolveA2AChannelHub(parsed.channel_id);
46477
46494
  if (hubAddr) a2aTarget = hubAddr;
46478
46495
  }
46479
- const roomId = (typeof parsed.room_id === "string" ? parsed.room_id : void 0) ?? channel2.lastInboundRoomId;
46480
46496
  if (a2aTarget && typeof a2aTarget === "string") {
46481
- await channel2.sendToAgent(a2aTarget, text);
46482
- } else if (roomId) {
46483
- await channel2.sendToRoom(roomId, text, {
46484
- messageType: parsed.message_type,
46485
- priority: parsed.priority,
46486
- metadata: parsed.metadata
46487
- });
46497
+ target = { kind: "a2a", hubAddress: a2aTarget };
46498
+ } else if (typeof parsed.room_id === "string") {
46499
+ target = { kind: "room", roomId: parsed.room_id };
46500
+ } else if (parsed.target === "context") {
46501
+ target = { kind: "context" };
46488
46502
  } else if (parsed.file_path && typeof parsed.file_path === "string") {
46489
- await channel2.sendWithAttachment(text, parsed.file_path, {
46490
- topicId: parsed.topicId
46491
- });
46503
+ const receipt2 = await channel2.deliver(
46504
+ { kind: "owner" },
46505
+ { type: "attachment", text, filePath: parsed.file_path },
46506
+ { topicId: parsed.topicId }
46507
+ );
46508
+ return {
46509
+ status: receipt2.ok ? 200 : 500,
46510
+ body: {
46511
+ ok: receipt2.ok,
46512
+ destination: receipt2.destination,
46513
+ ...receipt2.error ? { error: receipt2.error } : {}
46514
+ }
46515
+ };
46492
46516
  } else {
46493
- await channel2.send(text, {
46494
- topicId: parsed.topicId,
46495
- messageType: parsed.message_type,
46496
- metadata: parsed.metadata
46497
- });
46517
+ target = { kind: "owner" };
46498
46518
  }
46499
- return { status: 200, body: { ok: true } };
46519
+ const receipt = await channel2.deliver(
46520
+ target,
46521
+ { type: "text", text },
46522
+ {
46523
+ topicId: parsed.topicId,
46524
+ priority: parsed.priority,
46525
+ metadata: {
46526
+ ...parsed.metadata,
46527
+ ...parsed.message_type ? { message_type: parsed.message_type } : {}
46528
+ }
46529
+ }
46530
+ );
46531
+ return {
46532
+ status: receipt.ok ? 200 : 500,
46533
+ body: {
46534
+ ok: receipt.ok,
46535
+ destination: receipt.destination,
46536
+ ...receipt.error ? { error: receipt.error } : {}
46537
+ }
46538
+ };
46500
46539
  } catch (err) {
46501
46540
  return { status: 500, body: { ok: false, error: String(err) } };
46502
46541
  }
@@ -46513,12 +46552,19 @@ async function handleActionRequest(parsed, channel2) {
46513
46552
  detail: parsed.detail,
46514
46553
  estimated_cost: parsed.estimated_cost
46515
46554
  };
46516
- if (parsed.room_id && typeof parsed.room_id === "string") {
46517
- await channel2.sendActionConfirmationToRoom(parsed.room_id, confirmation);
46518
- } else {
46519
- await channel2.sendActionConfirmation(confirmation);
46520
- }
46521
- return { status: 200, body: { ok: true } };
46555
+ const target = parsed.room_id && typeof parsed.room_id === "string" ? { kind: "room", roomId: parsed.room_id } : { kind: "owner" };
46556
+ const receipt = await channel2.deliver(
46557
+ target,
46558
+ { type: "action_confirmation", confirmation }
46559
+ );
46560
+ return {
46561
+ status: receipt.ok ? 200 : 500,
46562
+ body: {
46563
+ ok: receipt.ok,
46564
+ destination: receipt.destination,
46565
+ ...receipt.error ? { error: receipt.error } : {}
46566
+ }
46567
+ };
46522
46568
  } catch (err) {
46523
46569
  return { status: 500, body: { ok: false, error: String(err) } };
46524
46570
  }
@@ -46562,6 +46608,16 @@ function handleStatusRequest(channel2) {
46562
46608
  }
46563
46609
  };
46564
46610
  }
46611
+ function handleTargetsRequest(channel2) {
46612
+ return {
46613
+ status: 200,
46614
+ body: {
46615
+ ok: true,
46616
+ targets: channel2.listTargets(),
46617
+ context: channel2.lastInboundRoomId ? { kind: "room", roomId: channel2.lastInboundRoomId } : { kind: "owner" }
46618
+ }
46619
+ };
46620
+ }
46565
46621
  var init_http_handlers = __esm({
46566
46622
  "src/http-handlers.ts"() {
46567
46623
  "use strict";
@@ -47541,6 +47597,171 @@ var init_channel = __esm({
47541
47597
  metadata
47542
47598
  });
47543
47599
  }
47600
+ // --- Unified Delivery Protocol ---
47601
+ /**
47602
+ * Canonical message dispatcher. ALL outbound messages should flow through this method.
47603
+ * Routes based on explicit target — never silently falls back to a room.
47604
+ */
47605
+ async deliver(target, content, options) {
47606
+ const ts = (/* @__PURE__ */ new Date()).toISOString();
47607
+ if (this._state === "idle" || this._state === "error") {
47608
+ return {
47609
+ ok: false,
47610
+ destination: { kind: "owner" },
47611
+ error: `Channel is in ${this._state} state`,
47612
+ timestamp: ts
47613
+ };
47614
+ }
47615
+ let resolved;
47616
+ if (target.kind === "context") {
47617
+ if (this._lastInboundRoomId) {
47618
+ resolved = { kind: "room", id: this._lastInboundRoomId };
47619
+ console.log(`[deliver] target=context\u2192room:${this._lastInboundRoomId.slice(0, 8)}...`);
47620
+ } else {
47621
+ resolved = { kind: "owner" };
47622
+ console.log(`[deliver] target=context\u2192owner`);
47623
+ }
47624
+ } else if (target.kind === "owner") {
47625
+ resolved = { kind: "owner" };
47626
+ } else if (target.kind === "room") {
47627
+ if (!this._persisted?.rooms?.[target.roomId]) {
47628
+ const err = `Room ${target.roomId} not found`;
47629
+ console.log(`[deliver] target=room:${target.roomId.slice(0, 8)}... content=${content.type} result=FAIL: ${err}`);
47630
+ return { ok: false, destination: { kind: "room", id: target.roomId }, error: err, timestamp: ts };
47631
+ }
47632
+ resolved = { kind: "room", id: target.roomId };
47633
+ } else if (target.kind === "a2a") {
47634
+ const channelEntry = this._persisted?.a2aChannels ? Object.values(this._persisted.a2aChannels).find((ch) => ch.hubAddress === target.hubAddress) : void 0;
47635
+ if (!channelEntry) {
47636
+ const err = `No A2A channel found for hub address: ${target.hubAddress}`;
47637
+ console.log(`[deliver] target=a2a:${target.hubAddress} content=${content.type} result=FAIL: ${err}`);
47638
+ return { ok: false, destination: { kind: "a2a", id: target.hubAddress }, error: err, timestamp: ts };
47639
+ }
47640
+ resolved = { kind: "a2a", id: target.hubAddress };
47641
+ } else {
47642
+ return { ok: false, destination: { kind: "owner" }, error: "Unknown target kind", timestamp: ts };
47643
+ }
47644
+ try {
47645
+ let decisionId;
47646
+ if (content.type === "text") {
47647
+ if (resolved.kind === "room") {
47648
+ await this.sendToRoom(resolved.id, content.text, {
47649
+ messageType: options?.metadata?.message_type,
47650
+ priority: options?.priority,
47651
+ metadata: options?.metadata
47652
+ });
47653
+ } else if (resolved.kind === "a2a") {
47654
+ await this.sendToAgent(resolved.id, content.text, {
47655
+ parentSpanId: options?.parentSpanId
47656
+ });
47657
+ } else {
47658
+ await this.send(content.text, {
47659
+ conversationId: options?.conversationId,
47660
+ topicId: options?.topicId,
47661
+ messageType: options?.metadata?.message_type,
47662
+ priority: options?.priority,
47663
+ metadata: options?.metadata
47664
+ });
47665
+ }
47666
+ } else if (content.type === "decision_request") {
47667
+ if (resolved.kind !== "owner") {
47668
+ const err = "Decision requests can only be sent to owner";
47669
+ console.log(`[deliver] target=${resolved.kind}:${resolved.id} content=decision_request result=FAIL: ${err}`);
47670
+ return { ok: false, destination: resolved, error: err, timestamp: ts };
47671
+ }
47672
+ decisionId = await this.sendDecisionRequest(content.request);
47673
+ } else if (content.type === "status_alert") {
47674
+ if (resolved.kind === "room") {
47675
+ const envelope = {
47676
+ title: content.alert.title,
47677
+ message: content.alert.message,
47678
+ severity: content.alert.severity,
47679
+ timestamp: ts
47680
+ };
47681
+ if (content.alert.detail !== void 0) envelope.detail = content.alert.detail;
47682
+ if (content.alert.detailFormat !== void 0) envelope.detail_format = content.alert.detailFormat;
47683
+ if (content.alert.category !== void 0) envelope.category = content.alert.category;
47684
+ await this.sendToRoom(resolved.id, JSON.stringify(envelope), {
47685
+ messageType: "status_alert",
47686
+ priority: content.alert.severity === "error" || content.alert.severity === "critical" ? "high" : "normal",
47687
+ metadata: { severity: content.alert.severity }
47688
+ });
47689
+ } else if (resolved.kind === "owner") {
47690
+ await this.sendStatusAlert(content.alert);
47691
+ } else {
47692
+ return { ok: false, destination: resolved, error: "Status alerts cannot be sent to A2A targets", timestamp: ts };
47693
+ }
47694
+ } else if (content.type === "action_confirmation") {
47695
+ if (resolved.kind === "room") {
47696
+ await this.sendActionConfirmationToRoom(resolved.id, content.confirmation);
47697
+ } else if (resolved.kind === "owner") {
47698
+ await this.sendActionConfirmation(content.confirmation);
47699
+ } else {
47700
+ return { ok: false, destination: resolved, error: "Action confirmations cannot be sent to A2A targets", timestamp: ts };
47701
+ }
47702
+ } else if (content.type === "artifact") {
47703
+ if (resolved.kind !== "owner") {
47704
+ return { ok: false, destination: resolved, error: "Artifacts can only be sent to owner", timestamp: ts };
47705
+ }
47706
+ await this.sendArtifact(content.artifact);
47707
+ } else if (content.type === "attachment") {
47708
+ if (resolved.kind !== "owner") {
47709
+ return { ok: false, destination: resolved, error: "Attachments can only be sent to owner", timestamp: ts };
47710
+ }
47711
+ await this.sendWithAttachment(content.text, content.filePath, {
47712
+ topicId: options?.topicId
47713
+ });
47714
+ }
47715
+ const targetLabel = resolved.kind === "owner" ? "owner" : `${resolved.kind}:${resolved.id?.slice(0, 8)}...`;
47716
+ console.log(`[deliver] target=${targetLabel} content=${content.type} result=ok`);
47717
+ return {
47718
+ ok: true,
47719
+ destination: resolved,
47720
+ queued: this._state !== "ready",
47721
+ decisionId,
47722
+ timestamp: ts
47723
+ };
47724
+ } catch (err) {
47725
+ const targetLabel = resolved.kind === "owner" ? "owner" : `${resolved.kind}:${resolved.id?.slice(0, 8)}...`;
47726
+ const errMsg = err instanceof Error ? err.message : String(err);
47727
+ console.log(`[deliver] target=${targetLabel} content=${content.type} result=FAIL: ${errMsg}`);
47728
+ return { ok: false, destination: resolved, error: errMsg, timestamp: ts };
47729
+ }
47730
+ }
47731
+ /**
47732
+ * Returns all available delivery destinations with availability status.
47733
+ */
47734
+ listTargets() {
47735
+ const targets = [
47736
+ {
47737
+ kind: "owner",
47738
+ id: "owner",
47739
+ label: "Owner (direct)",
47740
+ available: this._state === "ready" && this._sessions.size > 0
47741
+ }
47742
+ ];
47743
+ if (this._persisted?.rooms) {
47744
+ for (const room of Object.values(this._persisted.rooms)) {
47745
+ targets.push({
47746
+ kind: "room",
47747
+ id: room.roomId,
47748
+ label: room.name || `Room ${room.roomId.slice(0, 8)}`,
47749
+ available: this._state === "ready" && room.conversationIds.length > 0
47750
+ });
47751
+ }
47752
+ }
47753
+ if (this._persisted?.a2aChannels) {
47754
+ for (const ch of Object.values(this._persisted.a2aChannels)) {
47755
+ targets.push({
47756
+ kind: "a2a",
47757
+ id: ch.hubAddress,
47758
+ label: `A2A: ${ch.hubAddress}`,
47759
+ available: this._state === "ready" && !!ch.session?.ratchetState
47760
+ });
47761
+ }
47762
+ }
47763
+ return targets;
47764
+ }
47544
47765
  _sendHeartbeat() {
47545
47766
  if (this._state !== "ready" || !this._heartbeatCallback) return;
47546
47767
  const status = this._heartbeatCallback();
@@ -47659,9 +47880,13 @@ var init_channel = __esm({
47659
47880
  const result = handlers.handleStatusRequest(this);
47660
47881
  res.writeHead(result.status, { "Content-Type": "application/json" });
47661
47882
  res.end(JSON.stringify(result.body));
47883
+ } else if (req.method === "GET" && req.url === "/targets") {
47884
+ const result = handlers.handleTargetsRequest(this);
47885
+ res.writeHead(result.status, { "Content-Type": "application/json" });
47886
+ res.end(JSON.stringify(result.body));
47662
47887
  } else {
47663
47888
  res.writeHead(404, { "Content-Type": "application/json" });
47664
- res.end(JSON.stringify({ ok: false, error: "Not found. Use POST /send, POST /decision, POST /action, or GET /status" }));
47889
+ res.end(JSON.stringify({ ok: false, error: "Not found. Use POST /send, POST /decision, POST /action, GET /status, or GET /targets" }));
47665
47890
  }
47666
47891
  });
47667
47892
  this._httpServer.listen(port, "127.0.0.1", () => {
@@ -48270,10 +48495,11 @@ var init_channel = __esm({
48270
48495
  }
48271
48496
  if (data.event === "hub_identity_sync") {
48272
48497
  if (this._persisted && data.data?.hub_id) {
48273
- const changed = this._persisted.hubId !== data.data.hub_id;
48498
+ const changed = this._persisted.hubId !== data.data.hub_id || this._persisted.agentRole !== (data.data.agent_role ?? "peer");
48274
48499
  this._persisted.hubAddress = data.data.hub_address;
48275
48500
  this._persisted.hubId = data.data.hub_id;
48276
48501
  this._persisted.agentHubId = data.data.hub_id;
48502
+ this._persisted.agentRole = data.data.agent_role ?? "peer";
48277
48503
  if (changed) this._persistState();
48278
48504
  if (!this._telemetryReporter && this._persisted.deviceJwt && this._persisted.hubId) {
48279
48505
  this._telemetryReporter = new TelemetryReporter({
@@ -48295,6 +48521,14 @@ var init_channel = __esm({
48295
48521
  }
48296
48522
  this.emit("hub_identity_assigned", data.data);
48297
48523
  }
48524
+ if (data.event === "hub_identity_role_changed") {
48525
+ if (this._persisted && data.data?.agent_role) {
48526
+ this._persisted.agentRole = data.data.agent_role;
48527
+ this._persistState();
48528
+ console.log(`[SecureChannel] Agent role changed to: ${data.data.agent_role}`);
48529
+ }
48530
+ this.emit("hub_identity_role_changed", data.data);
48531
+ }
48298
48532
  if (data.event === "hub_identity_removed") {
48299
48533
  if (this._persisted) {
48300
48534
  delete this._persisted.hubAddress;
@@ -48961,6 +49195,9 @@ ${messageText}`;
48961
49195
  _resolveWorkspaceDir() {
48962
49196
  const homedir = process.env.HOME ?? process.env.USERPROFILE ?? "/tmp";
48963
49197
  const agentName = this.config.agentName;
49198
+ if (this._persisted?.agentRole === "lead") {
49199
+ return join3(homedir, ".openclaw", "workspace");
49200
+ }
48964
49201
  try {
48965
49202
  const configPath = join3(homedir, ".openclaw", "openclaw.json");
48966
49203
  const raw = __require("node:fs").readFileSync(configPath, "utf-8");
@@ -50001,6 +50238,13 @@ var init_cp = __esm({
50001
50238
  }
50002
50239
  });
50003
50240
 
50241
+ // src/types.ts
50242
+ var init_types = __esm({
50243
+ "src/types.ts"() {
50244
+ "use strict";
50245
+ }
50246
+ });
50247
+
50004
50248
  // src/account-config.ts
50005
50249
  var init_account_config = __esm({
50006
50250
  "src/account-config.ts"() {
@@ -50022,8 +50266,11 @@ var init_openclaw_plugin = __esm({
50022
50266
  var gateway_send_exports = {};
50023
50267
  __export(gateway_send_exports, {
50024
50268
  checkGateway: () => checkGateway,
50269
+ listTargets: () => listTargets,
50025
50270
  sendDecisionToOwner: () => sendDecisionToOwner,
50026
- sendToOwner: () => sendToOwner
50271
+ sendToOwner: () => sendToOwner,
50272
+ sendToRoom: () => sendToRoom,
50273
+ sendToTarget: () => sendToTarget
50027
50274
  });
50028
50275
  function resolveBaseUrl(options) {
50029
50276
  const host = options?.host ?? "127.0.0.1";
@@ -50091,6 +50338,88 @@ async function sendDecisionToOwner(request, options) {
50091
50338
  return { ok: false, error: friendlyError(err) };
50092
50339
  }
50093
50340
  }
50341
+ async function sendToRoom(roomId, text, options) {
50342
+ if (typeof text !== "string" || text.trim().length === 0) {
50343
+ return { ok: false, error: "Message text must be a non-empty string" };
50344
+ }
50345
+ if (!roomId) {
50346
+ return { ok: false, error: "Room ID is required" };
50347
+ }
50348
+ requestHeartbeatNow({ reason: "proactive-room-send" }).catch(() => {
50349
+ });
50350
+ try {
50351
+ const base = resolveBaseUrl(options);
50352
+ const sendPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/send" : "/send";
50353
+ const res = await fetch(`${base}${sendPath}`, {
50354
+ method: "POST",
50355
+ headers: { "Content-Type": "application/json" },
50356
+ body: JSON.stringify({ text, room_id: roomId }),
50357
+ signal: options?.signal
50358
+ });
50359
+ if (!res.ok) {
50360
+ const body = await res.text().catch(() => "");
50361
+ return { ok: false, error: `HTTP ${res.status}${body ? `: ${body}` : ""}` };
50362
+ }
50363
+ const data = await res.json();
50364
+ return { ok: data.ok ?? true };
50365
+ } catch (err) {
50366
+ return { ok: false, error: friendlyError(err) };
50367
+ }
50368
+ }
50369
+ async function sendToTarget(target, text, options) {
50370
+ if (typeof text !== "string" || text.trim().length === 0) {
50371
+ return { ok: false, error: "Message text must be a non-empty string" };
50372
+ }
50373
+ requestHeartbeatNow({ reason: "proactive-target-send" }).catch(() => {
50374
+ });
50375
+ try {
50376
+ const base = resolveBaseUrl(options);
50377
+ const sendPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/send" : "/send";
50378
+ const body = { text };
50379
+ if (target.startsWith("room:")) {
50380
+ body.room_id = target.slice(5);
50381
+ } else if (target.startsWith("a2a:")) {
50382
+ body.hub_address = target.slice(4);
50383
+ } else if (target === "context") {
50384
+ body.target = "context";
50385
+ }
50386
+ const res = await fetch(`${base}${sendPath}`, {
50387
+ method: "POST",
50388
+ headers: { "Content-Type": "application/json" },
50389
+ body: JSON.stringify(body),
50390
+ signal: options?.signal
50391
+ });
50392
+ if (!res.ok) {
50393
+ const respBody = await res.text().catch(() => "");
50394
+ return { ok: false, error: `HTTP ${res.status}${respBody ? `: ${respBody}` : ""}` };
50395
+ }
50396
+ const data = await res.json();
50397
+ return {
50398
+ ok: data.ok ?? true,
50399
+ destination: data.destination
50400
+ };
50401
+ } catch (err) {
50402
+ return { ok: false, error: friendlyError(err) };
50403
+ }
50404
+ }
50405
+ async function listTargets(options) {
50406
+ try {
50407
+ const base = resolveBaseUrl(options);
50408
+ const targetsPath = process.env.OPENCLAW_GATEWAY_URL ? "/agentvault/targets" : "/targets";
50409
+ const res = await fetch(`${base}${targetsPath}`, { signal: options?.signal });
50410
+ if (!res.ok) {
50411
+ return { ok: false, error: `HTTP ${res.status}` };
50412
+ }
50413
+ const data = await res.json();
50414
+ return {
50415
+ ok: true,
50416
+ targets: data.targets,
50417
+ context: data.context
50418
+ };
50419
+ } catch (err) {
50420
+ return { ok: false, error: friendlyError(err) };
50421
+ }
50422
+ }
50094
50423
  async function checkGateway(options) {
50095
50424
  try {
50096
50425
  const base = resolveBaseUrl(options);
@@ -50135,6 +50464,7 @@ var init_openclaw_entry = __esm({
50135
50464
  init_fetch_interceptor();
50136
50465
  init_http_handlers();
50137
50466
  init_openclaw_compat();
50467
+ init_types();
50138
50468
  }
50139
50469
  });
50140
50470
 
@@ -50816,7 +51146,7 @@ function createZodEnum(values, params) {
50816
51146
  });
50817
51147
  }
50818
51148
  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;
50819
- var init_types = __esm({
51149
+ var init_types2 = __esm({
50820
51150
  "../../node_modules/zod/v3/types.js"() {
50821
51151
  init_ZodError();
50822
51152
  init_errors();
@@ -54068,7 +54398,7 @@ var init_external = __esm({
54068
54398
  init_parseUtil();
54069
54399
  init_typeAliases();
54070
54400
  init_util();
54071
- init_types();
54401
+ init_types2();
54072
54402
  init_ZodError();
54073
54403
  }
54074
54404
  });
@@ -61568,7 +61898,7 @@ var init_v4 = __esm({
61568
61898
 
61569
61899
  // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
61570
61900
  var RELATED_TASK_META_KEY, JSONRPC_VERSION, AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskCreationParamsSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, JSONRPCNotificationSchema, JSONRPCResultResponseSchema, ErrorCode, JSONRPCErrorResponseSchema, JSONRPCMessageSchema, JSONRPCResponseSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, 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;
61571
- var init_types2 = __esm({
61901
+ var init_types3 = __esm({
61572
61902
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/types.js"() {
61573
61903
  init_v4();
61574
61904
  RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
@@ -63410,7 +63740,7 @@ var init_zod_json_schema_compat = __esm({
63410
63740
  var init_protocol = __esm({
63411
63741
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js"() {
63412
63742
  init_zod_compat();
63413
- init_types2();
63743
+ init_types3();
63414
63744
  init_interfaces();
63415
63745
  init_zod_json_schema_compat();
63416
63746
  }
@@ -70209,7 +70539,7 @@ var init_helpers = __esm({
70209
70539
  var init_server2 = __esm({
70210
70540
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js"() {
70211
70541
  init_protocol();
70212
- init_types2();
70542
+ init_types3();
70213
70543
  init_ajv_provider();
70214
70544
  init_zod_compat();
70215
70545
  init_server();
@@ -70251,7 +70581,7 @@ var init_mcp = __esm({
70251
70581
  init_server2();
70252
70582
  init_zod_compat();
70253
70583
  init_zod_json_schema_compat();
70254
- init_types2();
70584
+ init_types3();
70255
70585
  init_completable();
70256
70586
  init_uriTemplate();
70257
70587
  init_toolNameValidation();
@@ -70473,7 +70803,7 @@ var init_dist2 = __esm({
70473
70803
  // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js
70474
70804
  var init_webStandardStreamableHttp = __esm({
70475
70805
  "../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js"() {
70476
- init_types2();
70806
+ init_types3();
70477
70807
  }
70478
70808
  });
70479
70809
 
@@ -70518,7 +70848,7 @@ function parseSkillMd(content) {
70518
70848
  if (!frontmatter.name) return null;
70519
70849
  const instructionLines = lines.slice(endIdx + 1);
70520
70850
  const instructions = instructionLines.join("\n").trim();
70521
- return {
70851
+ const skill = {
70522
70852
  name: frontmatter.name,
70523
70853
  version: frontmatter.version,
70524
70854
  description: frontmatter.description,
@@ -70527,82 +70857,76 @@ function parseSkillMd(content) {
70527
70857
  slaDefinition: frontmatter.sla,
70528
70858
  instructions: instructions || void 0
70529
70859
  };
70860
+ if (frontmatter.agentVault) {
70861
+ const av = frontmatter.agentVault;
70862
+ if (av.certification) skill.certificationTier = av.certification;
70863
+ if (av.runtime?.capabilities) skill.toolsAllowed = av.runtime.capabilities;
70864
+ if (av.runtime?.forbidden) skill.toolsDenied = av.runtime.forbidden;
70865
+ if (av.runtime?.output_schema) skill.outputSchema = av.runtime.output_schema;
70866
+ if (av.model?.routing) skill.modelRouting = av.model.routing;
70867
+ if (av.model?.allowed) skill.allowedModels = av.model.allowed;
70868
+ if (av.model?.default) skill.defaultModel = av.model.default;
70869
+ if (av.integrity) skill.integrity = av.integrity;
70870
+ if (av.requiredPolicies) skill.requiredPolicies = av.requiredPolicies;
70871
+ }
70872
+ return skill;
70530
70873
  }
70531
70874
  function parseSimpleYaml(yaml) {
70532
70875
  const result = {};
70533
70876
  const lines = yaml.split("\n");
70534
- let currentKey = "";
70535
- let currentIndent = 0;
70536
- let nestedObj = null;
70877
+ const stack = [];
70878
+ let currentObj = result;
70879
+ function parseValue(raw) {
70880
+ const value = raw.replace(/^["']|["']$/g, "");
70881
+ const num = Number(value);
70882
+ if (!isNaN(num) && value !== "") return num;
70883
+ if (value === "true") return true;
70884
+ if (value === "false") return false;
70885
+ return value;
70886
+ }
70537
70887
  for (const line of lines) {
70538
70888
  const trimmed = line.trim();
70539
70889
  if (!trimmed || trimmed.startsWith("#")) continue;
70540
70890
  const indent = line.length - line.trimStart().length;
70541
- const inlineArrayMatch = trimmed.match(/^(\w[\w-]*)\s*:\s*\[(.+)\]$/);
70891
+ while (stack.length > 0 && indent <= stack[stack.length - 1].indent) {
70892
+ const popped = stack.pop();
70893
+ currentObj = stack.length > 0 ? stack[stack.length - 1].obj : result;
70894
+ currentObj[popped.key] = popped.obj;
70895
+ }
70896
+ const inlineArrayMatch = trimmed.match(/^(\w[\w_-]*)\s*:\s*\[(.+)\]$/);
70542
70897
  if (inlineArrayMatch) {
70543
70898
  const key = inlineArrayMatch[1];
70544
70899
  const values = inlineArrayMatch[2].split(",").map((v2) => v2.trim().replace(/^["']|["']$/g, ""));
70545
- if (nestedObj && indent > currentIndent) {
70546
- nestedObj[key] = values;
70900
+ if (stack.length > 0) {
70901
+ stack[stack.length - 1].obj[key] = values;
70547
70902
  } else {
70548
- if (nestedObj && currentKey) {
70549
- result[currentKey] = nestedObj;
70550
- nestedObj = null;
70551
- }
70552
- result[key] = values;
70903
+ currentObj[key] = values;
70553
70904
  }
70554
70905
  continue;
70555
70906
  }
70556
- const kvMatch = trimmed.match(/^(\w[\w-]*)\s*:\s*(.+)$/);
70557
- if (kvMatch && indent === 0) {
70558
- if (nestedObj && currentKey) {
70559
- result[currentKey] = nestedObj;
70560
- nestedObj = null;
70561
- }
70907
+ const kvMatch = trimmed.match(/^(\w[\w_-]*)\s*:\s*(.+)$/);
70908
+ if (kvMatch) {
70562
70909
  const key = kvMatch[1];
70563
- const value = kvMatch[2].replace(/^["']|["']$/g, "");
70564
- const num = Number(value);
70565
- if (!isNaN(num) && value !== "") {
70566
- result[key] = num;
70567
- } else if (value === "true") {
70568
- result[key] = true;
70569
- } else if (value === "false") {
70570
- result[key] = false;
70910
+ const val = parseValue(kvMatch[2]);
70911
+ if (stack.length > 0) {
70912
+ stack[stack.length - 1].obj[key] = val;
70571
70913
  } else {
70572
- result[key] = value;
70914
+ currentObj[key] = val;
70573
70915
  }
70574
70916
  continue;
70575
70917
  }
70576
- const nestedMatch = trimmed.match(/^(\w[\w-]*)\s*:$/);
70577
- if (nestedMatch && indent === 0) {
70578
- if (nestedObj && currentKey) {
70579
- result[currentKey] = nestedObj;
70580
- }
70581
- currentKey = nestedMatch[1];
70582
- currentIndent = indent;
70583
- nestedObj = {};
70918
+ const nestedMatch = trimmed.match(/^(\w[\w_-]*)\s*:$/);
70919
+ if (nestedMatch) {
70920
+ const key = nestedMatch[1];
70921
+ const newObj = {};
70922
+ stack.push({ key, obj: newObj, indent });
70584
70923
  continue;
70585
70924
  }
70586
- if (nestedObj && indent > 0) {
70587
- const nestedKv = trimmed.match(/^(\w[\w-]*)\s*:\s*(.+)$/);
70588
- if (nestedKv) {
70589
- const key = nestedKv[1];
70590
- const value = nestedKv[2].replace(/^["']|["']$/g, "");
70591
- const num = Number(value);
70592
- if (!isNaN(num) && value !== "") {
70593
- nestedObj[key] = num;
70594
- } else if (value === "true") {
70595
- nestedObj[key] = true;
70596
- } else if (value === "false") {
70597
- nestedObj[key] = false;
70598
- } else {
70599
- nestedObj[key] = value;
70600
- }
70601
- }
70602
- }
70603
70925
  }
70604
- if (nestedObj && currentKey) {
70605
- result[currentKey] = nestedObj;
70926
+ while (stack.length > 0) {
70927
+ const popped = stack.pop();
70928
+ const parent = stack.length > 0 ? stack[stack.length - 1].obj : result;
70929
+ parent[popped.key] = popped.obj;
70606
70930
  }
70607
70931
  return result;
70608
70932
  }
@@ -70627,12 +70951,21 @@ var init_skill_telemetry = __esm({
70627
70951
  }
70628
70952
  });
70629
70953
 
70954
+ // src/policy-enforcer.ts
70955
+ var init_policy_enforcer = __esm({
70956
+ async "src/policy-enforcer.ts"() {
70957
+ "use strict";
70958
+ await init_dist();
70959
+ }
70960
+ });
70961
+
70630
70962
  // src/index.ts
70631
70963
  var VERSION;
70632
70964
  var init_index = __esm({
70633
70965
  async "src/index.ts"() {
70634
70966
  "use strict";
70635
70967
  await init_channel();
70968
+ init_types();
70636
70969
  init_account_config();
70637
70970
  await init_openclaw_plugin();
70638
70971
  init_gateway_send();
@@ -70644,6 +70977,7 @@ var init_index = __esm({
70644
70977
  init_skill_manifest();
70645
70978
  init_skill_invoker();
70646
70979
  await init_skill_telemetry();
70980
+ await init_policy_enforcer();
70647
70981
  VERSION = "0.14.1";
70648
70982
  }
70649
70983
  });