shroud-privacy 2.0.2 → 2.0.4

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/hooks.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * OpenClaw lifecycle hooks for the Shroud privacy plugin.
3
3
  *
4
- * Registers 5 hooks:
5
- * 1. before_prompt_build (async) -- obfuscate user prompt via prependContext
6
- * 2. before_llm_send (async) -- obfuscate LLM input messages + return transformResponse for deobfuscation
7
- * 3. before_tool_call (async) -- deobfuscate tool params (+ depth tracking)
8
- * 4. tool_result_persist (SYNC) -- obfuscate tool result message
9
- * 5. message_sending (async) -- deobfuscate outbound message content (fallback)
4
+ * Registers 6 hooks:
5
+ * 1. before_prompt_build (async) -- obfuscate user prompt via prependContext
6
+ * 2. before_message_write (SYNC) -- obfuscate every message written to the session transcript
7
+ * 3. before_llm_send (async) -- obfuscate LLM input messages (only on platforms that support it)
8
+ * 4. before_tool_call (async) -- deobfuscate tool params (+ depth tracking)
9
+ * 5. tool_result_persist (SYNC) -- obfuscate tool result message
10
+ * 6. message_sending (async) -- deobfuscate outbound message content
10
11
  */
11
12
  import { Obfuscator } from "./obfuscator.js";
12
13
  export interface PluginApi {
package/dist/hooks.js CHANGED
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  * OpenClaw lifecycle hooks for the Shroud privacy plugin.
3
3
  *
4
- * Registers 5 hooks:
5
- * 1. before_prompt_build (async) -- obfuscate user prompt via prependContext
6
- * 2. before_llm_send (async) -- obfuscate LLM input messages + return transformResponse for deobfuscation
7
- * 3. before_tool_call (async) -- deobfuscate tool params (+ depth tracking)
8
- * 4. tool_result_persist (SYNC) -- obfuscate tool result message
9
- * 5. message_sending (async) -- deobfuscate outbound message content (fallback)
4
+ * Registers 6 hooks:
5
+ * 1. before_prompt_build (async) -- obfuscate user prompt via prependContext
6
+ * 2. before_message_write (SYNC) -- obfuscate every message written to the session transcript
7
+ * 3. before_llm_send (async) -- obfuscate LLM input messages (only on platforms that support it)
8
+ * 4. before_tool_call (async) -- deobfuscate tool params (+ depth tracking)
9
+ * 5. tool_result_persist (SYNC) -- obfuscate tool result message
10
+ * 6. message_sending (async) -- deobfuscate outbound message content
10
11
  */
11
12
  import { createHash, randomBytes } from "node:crypto";
12
13
  import { writeFileSync } from "node:fs";
@@ -256,6 +257,11 @@ export function registerHooks(api, obfuscator) {
256
257
  // 1. before_prompt_build (async): obfuscate user prompt
257
258
  // -----------------------------------------------------------------------
258
259
  api.on("before_prompt_build", async (event) => {
260
+ // Reset tool depth at the start of each turn — tool calls from the
261
+ // previous turn are complete, so the counter should not carry over.
262
+ if (obfuscator.toolDepth > 0) {
263
+ obfuscator.resetToolDepth();
264
+ }
259
265
  const prompt = event?.prompt;
260
266
  if (typeof prompt !== "string" || !prompt)
261
267
  return;
@@ -276,13 +282,51 @@ export function registerHooks(api, obfuscator) {
276
282
  };
277
283
  });
278
284
  // -----------------------------------------------------------------------
279
- // 2. before_llm_send (async): obfuscate LLM input + provide response deobfuscator
285
+ // 2. before_message_write (SYNC): obfuscate every message written to session
286
+ // This ensures the LLM always sees obfuscated history, even on platforms
287
+ // that don't support before_llm_send.
288
+ // -----------------------------------------------------------------------
289
+ api.on("before_message_write", (event) => {
290
+ if (!event?.message || typeof event.message !== "object")
291
+ return;
292
+ const msg = event.message;
293
+ // Obfuscate string content
294
+ if (typeof msg.content === "string") {
295
+ const result = obfuscator.obfuscate(msg.content);
296
+ if (result.entities.length === 0)
297
+ return;
298
+ dumpStatsFile(obfuscator);
299
+ return { message: { ...msg, content: result.obfuscated } };
300
+ }
301
+ // Obfuscate array-of-blocks content
302
+ if (Array.isArray(msg.content)) {
303
+ let changed = false;
304
+ const newContent = msg.content.map((block) => {
305
+ if (block && typeof block === "object" && typeof block.text === "string") {
306
+ const result = obfuscator.obfuscate(block.text);
307
+ if (result.entities.length > 0) {
308
+ changed = true;
309
+ return { ...block, text: result.obfuscated };
310
+ }
311
+ }
312
+ return block;
313
+ });
314
+ if (!changed)
315
+ return;
316
+ dumpStatsFile(obfuscator);
317
+ return { message: { ...msg, content: newContent } };
318
+ }
319
+ });
320
+ // -----------------------------------------------------------------------
321
+ // 3. before_llm_send (async): obfuscate LLM input + provide response deobfuscator
322
+ // Only fires on platforms that support this hook (e.g. custom forks).
323
+ // On standard OpenClaw, before_message_write handles obfuscation instead.
280
324
  // -----------------------------------------------------------------------
281
325
  api.on("before_llm_send", async (event) => {
282
326
  if (!Array.isArray(event?.messages))
283
327
  return;
284
- // Reset tool depth at the start of each LLM turn — tool calls from the
285
- // previous turn are complete, so the counter should not carry over.
328
+ // Reset tool depth (also done in before_prompt_build for platforms
329
+ // that don't support before_llm_send)
286
330
  if (obfuscator.toolDepth > 0) {
287
331
  obfuscator.resetToolDepth();
288
332
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "shroud-privacy",
3
3
  "name": "Shroud",
4
- "version": "2.0.2",
4
+ "version": "2.0.4",
5
5
  "description": "Privacy obfuscation with deterministic fake values and deobfuscation — PII never reaches the LLM, tool calls still work",
6
6
  "configSchema": {
7
7
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shroud-privacy",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Privacy obfuscation plugin for OpenClaw — detects sensitive data and replaces with deterministic fake values",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",