@coffeexdev/openclaw-sentinel 0.5.0 → 0.5.1

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/README.md CHANGED
@@ -146,7 +146,7 @@ Use `sentinel_control`:
146
146
  1. Sentinel evaluates conditions.
147
147
  2. On match, it dispatches a generic callback envelope (`type: "sentinel.callback"`) to `localDispatchBase + webhookPath`.
148
148
  3. The envelope includes stable keys (`intent`, `context`, `watcher`, `trigger`, bounded `payload`, `deliveryTargets`, `deliveryContext`, `source`) so downstream agent behavior is workflow-agnostic.
149
- 4. For `/hooks/sentinel`, Sentinel enqueues an instruction-prefixed system event plus structured JSON envelope and requests heartbeat wake.
149
+ 4. For `/hooks/sentinel`, Sentinel enqueues an instruction-prefixed system event plus structured JSON envelope with a cron-tagged callback context, then requests an immediate `cron:sentinel-callback` wake (avoids heartbeat-poll prompting).
150
150
  5. The hook route creates a **response-delivery contract** keyed by callback dedupe key, preserving original chat/session context (`deliveryContext`) and intended relay targets.
151
151
  6. OpenClaw processes each callback in an isolated hook session: per-watcher by default, or grouped when `hookSessionGroup` / `fire.sessionGroup` is set. Shared global hook-session mode is intentionally not supported.
152
152
  7. When hook-session LLM output arrives, Sentinel relays assistant-authored text to the original chat context. If no assistant output arrives before `hookResponseTimeoutMs`, optional fallback relay behavior is applied (`hookResponseFallbackMode`).
package/dist/index.js CHANGED
@@ -11,6 +11,9 @@ const DEFAULT_HOOK_RESPONSE_FALLBACK_MODE = "concise";
11
11
  const MAX_SENTINEL_WEBHOOK_BODY_BYTES = 64 * 1024;
12
12
  const MAX_SENTINEL_WEBHOOK_TEXT_CHARS = 8000;
13
13
  const MAX_SENTINEL_PAYLOAD_JSON_CHARS = 2500;
14
+ const SENTINEL_CALLBACK_WAKE_REASON = "cron:sentinel-callback";
15
+ const SENTINEL_CALLBACK_CONTEXT_KEY = "cron:sentinel-callback";
16
+ const HEARTBEAT_ACK_TOKEN_PATTERN = /\bHEARTBEAT_OK\b/gi;
14
17
  const SENTINEL_EVENT_INSTRUCTION_PREFIX = "SENTINEL_TRIGGER: This system event came from /hooks/sentinel. Evaluate action policy, decide whether to notify configured deliveryTargets, and execute safe follow-up actions.";
15
18
  const SUPPORTED_DELIVERY_CHANNELS = new Set([
16
19
  "telegram",
@@ -303,12 +306,16 @@ function buildRelayMessage(envelope) {
303
306
  if (contextSummary)
304
307
  lines.push(contextSummary);
305
308
  const text = lines.join("\n").trim();
306
- return text.length > 0 ? text : "Sentinel callback received.";
309
+ return text.length > 0
310
+ ? text
311
+ : "Sentinel callback received, but no assistant detail was generated.";
307
312
  }
308
313
  function normalizeAssistantRelayText(assistantTexts) {
309
314
  if (!Array.isArray(assistantTexts) || assistantTexts.length === 0)
310
315
  return undefined;
311
- const parts = assistantTexts.map((value) => value.trim()).filter(Boolean);
316
+ const parts = assistantTexts
317
+ .map((value) => value.replace(HEARTBEAT_ACK_TOKEN_PATTERN, "").trim())
318
+ .filter(Boolean);
312
319
  if (parts.length === 0)
313
320
  return undefined;
314
321
  return trimText(parts.join("\n\n"), MAX_SENTINEL_WEBHOOK_TEXT_CHARS);
@@ -658,9 +665,12 @@ export function createSentinelPlugin(overrides) {
658
665
  const envelope = buildSentinelEventEnvelope(payload);
659
666
  const sessionKey = buildIsolatedHookSessionKey(envelope, config);
660
667
  const text = buildSentinelSystemEvent(envelope);
661
- const enqueued = api.runtime.system.enqueueSystemEvent(text, { sessionKey });
668
+ const enqueued = api.runtime.system.enqueueSystemEvent(text, {
669
+ sessionKey,
670
+ contextKey: SENTINEL_CALLBACK_CONTEXT_KEY,
671
+ });
662
672
  api.runtime.system.requestHeartbeatNow({
663
- reason: "hook:sentinel",
673
+ reason: SENTINEL_CALLBACK_WAKE_REASON,
664
674
  sessionKey,
665
675
  });
666
676
  const relayTargets = inferRelayTargets(payload, envelope);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffeexdev/openclaw-sentinel",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Secure declarative gateway-native watcher plugin for OpenClaw",
5
5
  "keywords": [
6
6
  "openclaw",