@agentapprove/openclaw 0.1.6 → 0.1.7

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
@@ -35,22 +35,77 @@ function ensureLogFile() {
35
35
  if (stat.size > MAX_SIZE) {
36
36
  const content = readFileSync(DEBUG_LOG_PATH, "utf-8");
37
37
  writeFileSync(DEBUG_LOG_PATH, content.slice(-KEEP_SIZE), { mode: 384 });
38
- const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
39
- appendFileSync(DEBUG_LOG_PATH, `[${ts}] [openclaw-plugin] Log rotated (exceeded 5MB)
38
+ appendFileSync(DEBUG_LOG_PATH, `[${localTimestamp()}] [debug] Log rotated (exceeded 5MB, kept last 2MB)
40
39
  `);
41
40
  }
42
41
  } catch {
43
42
  }
44
43
  }
44
+ function localTimestamp() {
45
+ const d = /* @__PURE__ */ new Date();
46
+ const pad = (n) => String(n).padStart(2, "0");
47
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
48
+ }
45
49
  function debugLog(message, hookName = "openclaw-plugin") {
46
50
  try {
47
51
  ensureLogFile();
48
- const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
49
- appendFileSync(DEBUG_LOG_PATH, `[${ts}] [${hookName}] ${message}
52
+ appendFileSync(DEBUG_LOG_PATH, `[${localTimestamp()}] [${hookName}] ${message}
50
53
  `);
51
54
  } catch {
52
55
  }
53
56
  }
57
+ function debugLogRawInline(data) {
58
+ try {
59
+ ensureLogFile();
60
+ appendFileSync(DEBUG_LOG_PATH, `${data}
61
+ `);
62
+ } catch {
63
+ }
64
+ }
65
+ function safeStringify(value) {
66
+ try {
67
+ const seen = /* @__PURE__ */ new WeakSet();
68
+ return JSON.stringify(value, (_key, current) => {
69
+ if (typeof current === "bigint") return `BigInt(${current.toString()})`;
70
+ if (typeof current === "function") {
71
+ const fn = current;
72
+ return `[Function ${fn.name || "anonymous"}]`;
73
+ }
74
+ if (typeof current === "symbol") return current.toString();
75
+ if (current instanceof Error) {
76
+ return {
77
+ name: current.name,
78
+ message: current.message,
79
+ stack: current.stack
80
+ };
81
+ }
82
+ if (current && typeof current === "object") {
83
+ const obj = current;
84
+ if (seen.has(obj)) return "[Circular]";
85
+ seen.add(obj);
86
+ }
87
+ return current;
88
+ }) ?? "null";
89
+ } catch (error) {
90
+ const msg = error instanceof Error ? error.message : String(error);
91
+ return `"[Unserializable: ${msg}]"`;
92
+ }
93
+ }
94
+ function debugLogRaw(data, hookName = "openclaw-plugin") {
95
+ try {
96
+ ensureLogFile();
97
+ const ts = localTimestamp();
98
+ const rawData = typeof data === "string" ? data : safeStringify(data);
99
+ appendFileSync(
100
+ DEBUG_LOG_PATH,
101
+ `[${ts}] [${hookName}] === RAW INPUT ===
102
+ ${rawData}
103
+ [${ts}] [${hookName}] === END RAW ===
104
+ `
105
+ );
106
+ } catch {
107
+ }
108
+ }
54
109
 
55
110
  // src/e2e-crypto.ts
56
111
  function keyId(keyHex) {
@@ -331,7 +386,7 @@ function loadConfig(openclawConfig, logger) {
331
386
  failBehavior,
332
387
  privacyTier,
333
388
  debug,
334
- hookVersion: "1.1.3",
389
+ hookVersion: "1.1.4",
335
390
  agentName,
336
391
  e2eEnabled,
337
392
  e2eUserKey,
@@ -585,11 +640,11 @@ function getLocalConfigSetAt() {
585
640
 
586
641
  // src/api-client.ts
587
642
  var cachedPluginHash;
588
- function getPluginHash(pluginPath, debug = false) {
643
+ function getPluginHash(pluginPath, debug = false, hookName = "openclaw-plugin") {
589
644
  if (!cachedPluginHash) {
590
645
  cachedPluginHash = computePluginHash(pluginPath);
591
646
  if (cachedPluginHash && debug) {
592
- debugLog(`Plugin hash computed: ${cachedPluginHash.slice(0, 16)}...`);
647
+ debugLog(`Plugin hash computed: ${cachedPluginHash.slice(0, 16)}...`, hookName);
593
648
  }
594
649
  }
595
650
  return cachedPluginHash || "";
@@ -631,7 +686,7 @@ function httpPost(url, body, headers, timeoutMs) {
631
686
  req.end();
632
687
  });
633
688
  }
634
- async function sendApprovalRequest(request, config, pluginPath) {
689
+ async function sendApprovalRequest(request, config, pluginPath, hookName = "openclaw-plugin") {
635
690
  if (!config.token) {
636
691
  throw new Error("No Agent Approve token configured");
637
692
  }
@@ -639,13 +694,13 @@ async function sendApprovalRequest(request, config, pluginPath) {
639
694
  if (config.e2eEnabled && config.e2eUserKey) {
640
695
  payload = applyApprovalE2E(request, config.e2eUserKey, config.e2eServerKey);
641
696
  if (config.debug) {
642
- debugLog("E2E encryption applied to approval request");
697
+ debugLog("E2E encryption applied to approval request", hookName);
643
698
  }
644
699
  } else {
645
700
  payload = applyPrivacyFilter(request, config.privacyTier);
646
701
  }
647
702
  const bodyStr = JSON.stringify(payload);
648
- const pluginHash = getPluginHash(pluginPath, config.debug);
703
+ const pluginHash = getPluginHash(pluginPath, config.debug, hookName);
649
704
  const hmacHeaders = buildHMACHeaders(bodyStr, config.token, config.hookVersion, pluginHash);
650
705
  const headers = {
651
706
  "Authorization": `Bearer ${config.token}`,
@@ -653,11 +708,14 @@ async function sendApprovalRequest(request, config, pluginPath) {
653
708
  };
654
709
  const url = `${config.apiUrl}/${config.apiVersion}/approve`;
655
710
  if (config.debug) {
656
- debugLog(`Sending approval request to ${url} for tool: ${request.toolName}`);
711
+ debugLog(`Requesting approval from ${url}`, hookName);
712
+ debugLog(`=== SENT TO ${url} ===`, hookName);
713
+ debugLogRawInline(bodyStr);
714
+ debugLog("=== END SENT ===", hookName);
657
715
  }
658
716
  const response = await httpPost(url, bodyStr, headers, config.timeout * 1e3);
659
717
  if (config.debug) {
660
- debugLog(`Response status: ${response.status}, body: ${response.body.slice(0, 200)}`);
718
+ debugLog(`Response: ${response.body || "<empty>"}`, hookName);
661
719
  }
662
720
  if (response.status !== 200) {
663
721
  throw new Error(`API returned status ${response.status}: ${response.body.slice(0, 200)}`);
@@ -671,23 +729,23 @@ async function sendApprovalRequest(request, config, pluginPath) {
671
729
  processConfigSync(parsed, config);
672
730
  return parsed;
673
731
  }
674
- async function sendEvent(event, config, pluginPath) {
732
+ async function sendEvent(event, config, pluginPath, hookName = "openclaw-plugin") {
675
733
  if (!config.token) return;
676
734
  const eventType = event.eventType;
677
735
  const toolName = event.toolName;
678
736
  if (config.debug) {
679
- debugLog(`Sending ${eventType || "event"}${toolName ? ` (${toolName})` : ""} (privacy: ${config.privacyTier})`);
737
+ debugLog(`Sending ${eventType || "event"}${toolName ? ` (${toolName})` : ""} (privacy: ${config.privacyTier})`, hookName);
680
738
  }
681
739
  try {
682
740
  let payload = applyEventPrivacyFilter(event, config.privacyTier);
683
741
  if (config.e2eEnabled && config.e2eUserKey) {
684
742
  payload = applyEventE2E(payload, config.e2eUserKey);
685
743
  if (config.debug) {
686
- debugLog(`E2E applied to event (type=${eventType})`);
744
+ debugLog(`E2E applied to event (type=${eventType})`, hookName);
687
745
  }
688
746
  }
689
747
  const bodyStr = JSON.stringify(payload);
690
- const pluginHash = getPluginHash(pluginPath, config.debug);
748
+ const pluginHash = getPluginHash(pluginPath, config.debug, hookName);
691
749
  const hmacHeaders = buildHMACHeaders(bodyStr, config.token, config.hookVersion, pluginHash);
692
750
  const headers = {
693
751
  "Authorization": `Bearer ${config.token}`,
@@ -695,13 +753,13 @@ async function sendEvent(event, config, pluginPath) {
695
753
  };
696
754
  const url = `${config.apiUrl}/${config.apiVersion}/events`;
697
755
  if (config.debug) {
698
- debugLog(`=== SENT TO ${url} ===`);
699
- debugLog(bodyStr.slice(0, 500));
700
- debugLog("=== END SENT ===");
756
+ debugLog(`=== SENT TO ${url} ===`, hookName);
757
+ debugLogRawInline(bodyStr);
758
+ debugLog("=== END SENT ===", hookName);
701
759
  }
702
760
  const response = await httpPost(url, bodyStr, headers, 5e3);
703
761
  if (config.debug) {
704
- debugLog(`send_event response: ${response.body.slice(0, 200)}`);
762
+ debugLog(`send_event response: ${response.body || "<empty>"}`, hookName);
705
763
  }
706
764
  if (response.status === 200) {
707
765
  try {
@@ -712,7 +770,7 @@ async function sendEvent(event, config, pluginPath) {
712
770
  }
713
771
  } catch (err) {
714
772
  if (config.debug) {
715
- debugLog(`Failed to send ${eventType || "event"}: ${err instanceof Error ? err.message : String(err)}`);
773
+ debugLog(`Failed to send ${eventType || "event"}: ${err instanceof Error ? err.message : String(err)}`, hookName);
716
774
  }
717
775
  }
718
776
  }
@@ -728,6 +786,19 @@ var gatewaySessionId = randomBytes2(12).toString("hex");
728
786
  var DEDUP_WINDOW_MS = 1200;
729
787
  var DEDUP_MAX_SIZE = 300;
730
788
  var recentCompletions = /* @__PURE__ */ new Map();
789
+ var HOOK_PLUGIN = "openclaw-plugin";
790
+ var HOOK_BEFORE_TOOL = "openclaw-before-tool";
791
+ var HOOK_AFTER_TOOL = "openclaw-after-tool";
792
+ var HOOK_SESSION_START = "openclaw-session-start";
793
+ var HOOK_SESSION_END = "openclaw-session-end";
794
+ var HOOK_LLM_INPUT = "openclaw-llm-input";
795
+ var HOOK_LLM_OUTPUT = "openclaw-llm-output";
796
+ var HOOK_AGENT_END = "openclaw-agent-end";
797
+ var HOOK_BEFORE_COMPACTION = "openclaw-before-compaction";
798
+ var HOOK_SUBAGENT_SPAWNED = "openclaw-subagent-spawned";
799
+ var HOOK_SUBAGENT_ENDED = "openclaw-subagent-ended";
800
+ var HOOK_COMMAND = "openclaw-command";
801
+ var HOOK_MESSAGE = "openclaw-message";
731
802
  function resolveConversationId() {
732
803
  return gatewaySessionId;
733
804
  }
@@ -826,10 +897,10 @@ function extractResultPreview(toolName, params, result, maxLen = 300) {
826
897
  if (str.length <= maxLen) return str;
827
898
  return str.slice(0, maxLen) + "...";
828
899
  }
829
- function handleFailBehavior(config, error, toolName, logger) {
900
+ function handleFailBehavior(config, error, toolName, logger, hookName = HOOK_PLUGIN) {
830
901
  logger.warn(`Agent Approve API error for tool "${toolName}": ${error.message}`);
831
902
  if (config.debug) {
832
- debugLog(`API error: ${error.message}, failBehavior: ${config.failBehavior}`);
903
+ debugLog(`API error: ${error.message}, failBehavior: ${config.failBehavior}`, hookName);
833
904
  }
834
905
  switch (config.failBehavior) {
835
906
  case "deny":
@@ -854,14 +925,22 @@ function register(api) {
854
925
  if (config.debug) {
855
926
  const e2eStatus = !config.e2eEnabled ? "disabled" : !config.e2eUserKey ? "enabled (key missing)" : "enabled";
856
927
  debugLog(
857
- `Plugin loaded: v${config.hookVersion}, api=${config.apiUrl}, privacy=${config.privacyTier}, e2e=${e2eStatus}, debug=${config.debug}`
928
+ `Plugin loaded: v${config.hookVersion}, api=${config.apiUrl}, privacy=${config.privacyTier}, e2e=${e2eStatus}, debug=${config.debug}`,
929
+ HOOK_PLUGIN
858
930
  );
859
- debugLog(`Full config: agent=${config.agentName}, timeout=${config.timeout}s, fail=${config.failBehavior}`);
931
+ debugLog(`Full config: agent=${config.agentName}, timeout=${config.timeout}s, fail=${config.failBehavior}`, HOOK_PLUGIN);
860
932
  }
861
933
  api.on("before_tool_call", async (event, ctx) => {
934
+ if (config.debug) {
935
+ debugLogRaw({ event, ctx }, HOOK_BEFORE_TOOL);
936
+ debugLog("Started before_tool_call hook", HOOK_BEFORE_TOOL);
937
+ }
862
938
  const conversationId = resolveConversationId();
863
939
  const { toolType, displayName } = classifyTool(event.toolName, event.params);
864
940
  const command = extractCommand(event.toolName, event.params);
941
+ if (config.debug) {
942
+ debugLog(`Tool: ${displayName} (${toolType}) [agent: ${config.agentName}]`, HOOK_BEFORE_TOOL);
943
+ }
865
944
  const request = {
866
945
  toolName: displayName,
867
946
  toolType,
@@ -875,15 +954,18 @@ function register(api) {
875
954
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
876
955
  };
877
956
  try {
878
- const response = await sendApprovalRequest(request, config, pluginFilePath);
957
+ const response = await sendApprovalRequest(request, config, pluginFilePath, HOOK_BEFORE_TOOL);
958
+ if (config.debug) {
959
+ debugLog(`Decision: ${response.decision}, Reason: ${response.reason || ""}`, HOOK_BEFORE_TOOL);
960
+ }
879
961
  if (response.decision === "approve" || response.decision === "allow") {
880
962
  if (config.debug) {
881
- debugLog(`Tool "${event.toolName}" approved${response.reason ? ": " + response.reason : ""}`);
963
+ debugLog("Tool approved", HOOK_BEFORE_TOOL);
882
964
  }
883
965
  return void 0;
884
966
  }
885
967
  if (config.debug) {
886
- debugLog(`Tool "${event.toolName}" denied${response.reason ? ": " + response.reason : ""}`);
968
+ debugLog("Tool denied", HOOK_BEFORE_TOOL);
887
969
  }
888
970
  return {
889
971
  block: true,
@@ -894,15 +976,19 @@ function register(api) {
894
976
  config,
895
977
  error instanceof Error ? error : new Error(String(error)),
896
978
  event.toolName,
897
- api.logger
979
+ api.logger,
980
+ HOOK_BEFORE_TOOL
898
981
  );
899
982
  }
900
983
  });
901
984
  api.on("after_tool_call", async (event, ctx) => {
985
+ if (config.debug) {
986
+ debugLogRaw({ event, ctx }, HOOK_AFTER_TOOL);
987
+ }
902
988
  const conversationId = resolveConversationId();
903
989
  if (isDuplicateCompletion(event.toolName, event.params)) {
904
990
  if (config.debug) {
905
- debugLog(`Skipping duplicate tool_complete for "${event.toolName}"`);
991
+ debugLog(`Skipping duplicate tool_complete for "${event.toolName}"`, HOOK_AFTER_TOOL);
906
992
  }
907
993
  return;
908
994
  }
@@ -921,13 +1007,14 @@ function register(api) {
921
1007
  response: event.error || resultPreview || void 0,
922
1008
  durationMs: event.durationMs,
923
1009
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
924
- }, config, pluginFilePath);
1010
+ }, config, pluginFilePath, HOOK_AFTER_TOOL);
925
1011
  });
926
1012
  api.on("session_start", async (event, ctx) => {
927
- const conversationId = resolveConversationId();
928
1013
  if (config.debug) {
929
- debugLog(`Session started: ${event.sessionId}${event.resumedFrom ? ` (resumed from ${event.resumedFrom})` : ""}`);
1014
+ debugLogRaw({ event, ctx }, HOOK_SESSION_START);
1015
+ debugLog(`Session started: ${event.sessionId}${event.resumedFrom ? ` (resumed from ${event.resumedFrom})` : ""}`, HOOK_SESSION_START);
930
1016
  }
1017
+ const conversationId = resolveConversationId();
931
1018
  void sendEvent({
932
1019
  eventType: "session_start",
933
1020
  agent: config.agentName,
@@ -935,13 +1022,14 @@ function register(api) {
935
1022
  sessionId: conversationId,
936
1023
  conversationId,
937
1024
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
938
- }, config, pluginFilePath);
1025
+ }, config, pluginFilePath, HOOK_SESSION_START);
939
1026
  });
940
1027
  api.on("session_end", async (event, ctx) => {
941
- const conversationId = resolveConversationId();
942
1028
  if (config.debug) {
943
- debugLog(`Session ended: ${event.sessionId} (${event.messageCount} messages, ${event.durationMs ?? "?"}ms)`);
1029
+ debugLogRaw({ event, ctx }, HOOK_SESSION_END);
1030
+ debugLog(`Session ended: ${event.sessionId} (${event.messageCount} messages, ${event.durationMs ?? "?"}ms)`, HOOK_SESSION_END);
944
1031
  }
1032
+ const conversationId = resolveConversationId();
945
1033
  void sendEvent({
946
1034
  eventType: "session_end",
947
1035
  agent: config.agentName,
@@ -951,13 +1039,14 @@ function register(api) {
951
1039
  durationMs: event.durationMs,
952
1040
  sessionStats: { messageCount: event.messageCount },
953
1041
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
954
- }, config, pluginFilePath);
1042
+ }, config, pluginFilePath, HOOK_SESSION_END);
955
1043
  });
956
1044
  api.on("llm_input", async (event, ctx) => {
957
- const conversationId = resolveConversationId();
958
1045
  if (config.debug) {
959
- debugLog(`LLM input: model=${event.model}, prompt length=${event.prompt?.length ?? 0}`);
1046
+ debugLogRaw({ event, ctx }, HOOK_LLM_INPUT);
1047
+ debugLog(`LLM input: model=${event.model}, prompt length=${event.prompt?.length ?? 0}`, HOOK_LLM_INPUT);
960
1048
  }
1049
+ const conversationId = resolveConversationId();
961
1050
  void sendEvent({
962
1051
  eventType: "user_prompt",
963
1052
  agent: config.agentName,
@@ -968,14 +1057,15 @@ function register(api) {
968
1057
  prompt: event.prompt,
969
1058
  textLength: event.prompt?.length ?? 0,
970
1059
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
971
- }, config, pluginFilePath);
1060
+ }, config, pluginFilePath, HOOK_LLM_INPUT);
972
1061
  });
973
1062
  api.on("llm_output", async (event, ctx) => {
974
1063
  const conversationId = resolveConversationId();
975
1064
  const responseText = event.assistantTexts?.join("\n") || "";
976
1065
  const textLength = responseText.length;
977
1066
  if (config.debug) {
978
- debugLog(`LLM output: model=${event.model}, length=${textLength}${event.usage?.total ? `, tokens=${event.usage.total}` : ""}`);
1067
+ debugLogRaw({ event, ctx }, HOOK_LLM_OUTPUT);
1068
+ debugLog(`LLM output: model=${event.model}, length=${textLength}${event.usage?.total ? `, tokens=${event.usage.total}` : ""}`, HOOK_LLM_OUTPUT);
979
1069
  }
980
1070
  void sendEvent({
981
1071
  eventType: "response",
@@ -988,13 +1078,14 @@ function register(api) {
988
1078
  textPreview: responseText.slice(0, 200),
989
1079
  textLength,
990
1080
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
991
- }, config, pluginFilePath);
1081
+ }, config, pluginFilePath, HOOK_LLM_OUTPUT);
992
1082
  });
993
1083
  api.on("agent_end", async (event, ctx) => {
994
- const conversationId = resolveConversationId();
995
1084
  if (config.debug) {
996
- debugLog(`Agent ended: success=${event.success}${event.durationMs ? `, duration=${event.durationMs}ms` : ""}${event.error ? `, error=${event.error}` : ""}`);
1085
+ debugLogRaw({ event, ctx }, HOOK_AGENT_END);
1086
+ debugLog(`Agent ended: success=${event.success}${event.durationMs ? `, duration=${event.durationMs}ms` : ""}${event.error ? `, error=${event.error}` : ""}`, HOOK_AGENT_END);
997
1087
  }
1088
+ const conversationId = resolveConversationId();
998
1089
  void sendEvent({
999
1090
  eventType: "stop",
1000
1091
  agent: config.agentName,
@@ -1005,13 +1096,14 @@ function register(api) {
1005
1096
  durationMs: event.durationMs,
1006
1097
  response: event.error || void 0,
1007
1098
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1008
- }, config, pluginFilePath);
1099
+ }, config, pluginFilePath, HOOK_AGENT_END);
1009
1100
  });
1010
1101
  api.on("before_compaction", async (event, ctx) => {
1011
- const conversationId = resolveConversationId();
1012
1102
  if (config.debug) {
1013
- debugLog(`Context compaction: ${event.messageCount} messages${event.tokenCount ? `, ${event.tokenCount} tokens` : ""}`);
1103
+ debugLogRaw({ event, ctx }, HOOK_BEFORE_COMPACTION);
1104
+ debugLog(`Context compaction: ${event.messageCount} messages${event.tokenCount ? `, ${event.tokenCount} tokens` : ""}`, HOOK_BEFORE_COMPACTION);
1014
1105
  }
1106
+ const conversationId = resolveConversationId();
1015
1107
  void sendEvent({
1016
1108
  eventType: "context_compact",
1017
1109
  agent: config.agentName,
@@ -1020,13 +1112,14 @@ function register(api) {
1020
1112
  conversationId,
1021
1113
  trigger: `${event.messageCount} messages${event.tokenCount ? `, ${event.tokenCount} tokens` : ""}`,
1022
1114
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1023
- }, config, pluginFilePath);
1115
+ }, config, pluginFilePath, HOOK_BEFORE_COMPACTION);
1024
1116
  });
1025
1117
  api.on("subagent_spawned", async (event, ctx) => {
1026
- const conversationId = resolveConversationId();
1027
1118
  if (config.debug) {
1028
- debugLog(`Subagent spawned: ${event.agentId} (${event.mode}${event.label ? `, label=${event.label}` : ""})`);
1119
+ debugLogRaw({ event, ctx }, HOOK_SUBAGENT_SPAWNED);
1120
+ debugLog(`Subagent spawned: ${event.agentId} (${event.mode}${event.label ? `, label=${event.label}` : ""})`, HOOK_SUBAGENT_SPAWNED);
1029
1121
  }
1122
+ const conversationId = resolveConversationId();
1030
1123
  void sendEvent({
1031
1124
  eventType: "subagent_start",
1032
1125
  agent: config.agentName,
@@ -1037,13 +1130,14 @@ function register(api) {
1037
1130
  subagentMode: event.mode,
1038
1131
  subagentLabel: event.label,
1039
1132
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1040
- }, config, pluginFilePath);
1133
+ }, config, pluginFilePath, HOOK_SUBAGENT_SPAWNED);
1041
1134
  });
1042
1135
  api.on("subagent_ended", async (event, ctx) => {
1043
- const conversationId = resolveConversationId();
1044
1136
  if (config.debug) {
1045
- debugLog(`Subagent ended: ${event.targetKind} reason=${event.reason}${event.outcome ? `, outcome=${event.outcome}` : ""}`);
1137
+ debugLogRaw({ event, ctx }, HOOK_SUBAGENT_ENDED);
1138
+ debugLog(`Subagent ended: ${event.targetKind} reason=${event.reason}${event.outcome ? `, outcome=${event.outcome}` : ""}`, HOOK_SUBAGENT_ENDED);
1046
1139
  }
1140
+ const conversationId = resolveConversationId();
1047
1141
  void sendEvent({
1048
1142
  eventType: "subagent_stop",
1049
1143
  agent: config.agentName,
@@ -1054,7 +1148,7 @@ function register(api) {
1054
1148
  subagentType: event.targetKind,
1055
1149
  response: event.error || void 0,
1056
1150
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1057
- }, config, pluginFilePath);
1151
+ }, config, pluginFilePath, HOOK_SUBAGENT_ENDED);
1058
1152
  });
1059
1153
  api.registerHook(
1060
1154
  ["command:new", "command:stop", "command:reset"],
@@ -1065,7 +1159,8 @@ function register(api) {
1065
1159
  reset: "session_start"
1066
1160
  };
1067
1161
  if (config.debug) {
1068
- debugLog(`Command event: ${event.action}`);
1162
+ debugLogRaw(event, HOOK_COMMAND);
1163
+ debugLog(`Command event: ${event.action}`, HOOK_COMMAND);
1069
1164
  }
1070
1165
  void sendEvent({
1071
1166
  toolName: `command:${event.action}`,
@@ -1076,7 +1171,7 @@ function register(api) {
1076
1171
  sessionId: resolveConversationId(),
1077
1172
  conversationId: resolveConversationId(),
1078
1173
  timestamp: event.timestamp.toISOString()
1079
- }, config, pluginFilePath);
1174
+ }, config, pluginFilePath, HOOK_COMMAND);
1080
1175
  },
1081
1176
  { name: "agentapprove-command-monitor", description: "Log command events to Agent Approve" }
1082
1177
  );
@@ -1088,7 +1183,8 @@ function register(api) {
1088
1183
  const peer = isInbound ? event.context.from : event.context.to;
1089
1184
  const channelLabel = [provider, peer].filter(Boolean).join(":") || void 0;
1090
1185
  if (config.debug) {
1091
- debugLog(`Message event: ${event.action} ${channelLabel || "(no channel)"}`);
1186
+ debugLogRaw(event, HOOK_MESSAGE);
1187
+ debugLog(`Message event: ${event.action} ${channelLabel || "(no channel)"}`, HOOK_MESSAGE);
1092
1188
  }
1093
1189
  const payload = {
1094
1190
  toolName: `message:${event.action}`,
@@ -1110,7 +1206,7 @@ function register(api) {
1110
1206
  payload.prompt = `${peer}: ${content}`;
1111
1207
  }
1112
1208
  }
1113
- void sendEvent(payload, config, pluginFilePath);
1209
+ void sendEvent(payload, config, pluginFilePath, HOOK_MESSAGE);
1114
1210
  },
1115
1211
  { name: "agentapprove-session-monitor", description: "Log message events to Agent Approve" }
1116
1212
  );
@@ -2,7 +2,7 @@
2
2
  "id": "openclaw",
3
3
  "name": "Agent Approve",
4
4
  "description": "Mobile approval for AI agent tool execution. Approve or deny tool calls from your iPhone and Apple Watch.",
5
- "version": "0.1.6",
5
+ "version": "0.1.7",
6
6
  "homepage": "https://agentapprove.com",
7
7
  "configSchema": {
8
8
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentapprove/openclaw",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "Agent Approve plugin for OpenClaw - approve or deny AI agent tool calls from your iPhone and Apple Watch",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {