entroly-openclaw 1.0.80 → 1.0.82

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
@@ -22,12 +22,33 @@ Install the Python engine, then install the publicly verifiable OpenClaw plugin
22
22
  package from npm:
23
23
 
24
24
  ```bash
25
- pip install "entroly>=1.0.80"
25
+ pip install "entroly>=1.0.82"
26
26
  openclaw plugins install npm:entroly-openclaw
27
27
  openclaw plugins enable entroly
28
28
  openclaw gateway restart
29
29
  ```
30
30
 
31
+ The plugin starts a local Python subprocess for context assembly. That child
32
+ receives only the operating-system paths and Entroly-local settings it needs;
33
+ provider API keys, cloud credentials, registry tokens, and unrelated host
34
+ environment variables are not inherited. OpenClaw remains the sole owner of
35
+ provider authentication.
36
+
37
+ Local receipts are enabled by default because they make context decisions
38
+ auditable. They contain hashes, counts, estimates, warnings, and decision
39
+ metadata rather than conversation text, and are bounded by file-count and byte
40
+ quotas. To opt out of persistence, set:
41
+
42
+ ```json5
43
+ {
44
+ plugins: {
45
+ entries: {
46
+ entroly: { config: { writeReceipts: false } }
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
31
52
  ClawHub is an optional registry source. Use it only when
32
53
  `openclaw plugins search "entroly"` returns a current public package and its
33
54
  install hint. Do not guess a ClawHub slug or treat unpublished metadata as an
@@ -36,7 +57,7 @@ installable release.
36
57
  From an Entroly source checkout:
37
58
 
38
59
  ```bash
39
- pip install "entroly>=1.0.80"
60
+ pip install "entroly>=1.0.82"
40
61
  openclaw plugins install ./integrations/openclaw
41
62
  openclaw plugins enable entroly
42
63
  openclaw gateway restart
@@ -97,8 +118,10 @@ digest, native window, output reserve, safety reserve, and source.
97
118
 
98
119
  Context-budget discovery is local and enabled by default. It does not enable
99
120
  remote provider discovery or send credentials anywhere. Local Ollama/LM Studio
100
- and remote OpenRouter discovery remain separate operator opt-ins through
101
- Entroly's model-registry environment controls. Disable this fallback with
121
+ discovery and a local `ENTROLY_MODEL_REGISTRY` override remain explicit
122
+ operator controls. Remote OpenRouter discovery is deliberately unavailable
123
+ inside the OpenClaw bridge because provider credentials do not cross the
124
+ subprocess boundary. Disable local fallback with
102
125
  `autoDiscoverContextBudget: false`.
103
126
 
104
127
  For a custom model that neither OpenClaw nor trusted registry metadata can
@@ -211,6 +234,8 @@ archive receipts or raise `receiptMaxFiles` / `receiptMaxBytes` explicitly.
211
234
 
212
235
  ## Safety contract
213
236
 
237
+ - Provider API keys and unrelated host secrets are removed from the local
238
+ Python bridge environment before it starts.
214
239
  - System and developer messages are never modified.
215
240
  - Signed text, thinking/reasoning, images, tool calls, tool-result metadata,
216
241
  opaque provider signatures, and unknown content blocks are never modified.
package/bridge-client.js CHANGED
@@ -3,6 +3,51 @@ import readline from "node:readline";
3
3
 
4
4
  export const ENTROLY_BRIDGE_SCHEMA = "entroly.openclaw.bridge.v2";
5
5
 
6
+ const BRIDGE_ENVIRONMENT_ALLOWLIST = new Set([
7
+ "APPDATA",
8
+ "COMSPEC",
9
+ "ENTROLY_AIR_GAP",
10
+ "ENTROLY_DISABLE_TELEMETRY",
11
+ "ENTROLY_DISCOVER_LOCAL_MODELS",
12
+ "ENTROLY_LMSTUDIO_BASE",
13
+ "ENTROLY_MODEL_DISCOVERY_MAX",
14
+ "ENTROLY_MODEL_DISCOVERY_TIMEOUT",
15
+ "ENTROLY_MODEL_REGISTRY",
16
+ "ENTROLY_OLLAMA_BASE",
17
+ "ENTROLY_OLLAMA_INSPECT_CONTEXT",
18
+ "ENTROLY_OPENCLAW_RECEIPT_KEY_FILE",
19
+ "ENTROLY_UNKNOWN_MODEL_CONTEXT",
20
+ "HOME",
21
+ "HOMEDRIVE",
22
+ "HOMEPATH",
23
+ "LANG",
24
+ "LC_ALL",
25
+ "LC_CTYPE",
26
+ "LOCALAPPDATA",
27
+ "PATH",
28
+ "PATHEXT",
29
+ "SYSTEMDRIVE",
30
+ "SYSTEMROOT",
31
+ "TEMP",
32
+ "TMP",
33
+ "TMPDIR",
34
+ "TZ",
35
+ "USERPROFILE",
36
+ "WINDIR",
37
+ "XDG_STATE_HOME",
38
+ ]);
39
+
40
+ export function buildBridgeEnvironment(source = {}) {
41
+ return Object.fromEntries(
42
+ Object.entries(source).filter(
43
+ ([name, value]) =>
44
+ value !== undefined &&
45
+ value !== null &&
46
+ BRIDGE_ENVIRONMENT_ALLOWLIST.has(name.toUpperCase()),
47
+ ),
48
+ );
49
+ }
50
+
6
51
  export function validateBridgeHealth(result) {
7
52
  if (
8
53
  !result ||
@@ -30,7 +75,7 @@ export class EntrolyBridgeClient {
30
75
  this.timeoutMs = timeoutMs;
31
76
  this.logger = logger;
32
77
  this.spawnProcess = spawnProcess;
33
- this.environment = environment;
78
+ this.environment = buildBridgeEnvironment(environment);
34
79
  this.nextId = 1;
35
80
  this.pending = new Map();
36
81
  this.process = undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "entroly-openclaw",
3
- "version": "1.0.80",
3
+ "version": "1.0.82",
4
4
  "description": "Provider-independent, auditable context engineering for every OpenClaw model route",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/proof-hooks.js CHANGED
@@ -6,15 +6,50 @@ function sha256(value) {
6
6
  return createHash("sha256").update(String(value), "utf8").digest("hex");
7
7
  }
8
8
 
9
- function safeDiagnostic(value, limit = 400) {
10
- return String(value?.message ?? value ?? "unknown error")
9
+ // Diagnostics can contain provider text, tool names, bridge errors, or recovered
10
+ // material. Treat them as untrusted display data. Canonicalize before redaction
11
+ // so format/control characters cannot be inserted into credential markers to
12
+ // evade secret detection, then escape display syntax and truncate by code point.
13
+ const DISPLAY_WHITESPACE = /[\t\n\r\f\v\u0085\u2028\u2029]+/gu;
14
+ const UNSAFE_FOR_DISPLAY = /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/gu;
15
+ const MARKDOWN_DELIMITERS = /([\\`*_[\]{}()<>#+.!|~-])/g;
16
+ const AUTH_SCHEME = /\b(Basic|Bearer)\s+[^\s,;]+/gi;
17
+ const SECRET_FIELD =
18
+ /["']?\b(api[_-]?key|authorization|password|secret|token)\b["']?\s*[:=]\s*(?:"[^"]*(?:"|$)|'[^']*(?:'|$)|(?:Basic|Bearer)\s+[^\s,;]+|[^\s,;"']+)/gi;
19
+
20
+ function diagnosticSource(value) {
21
+ try {
22
+ const candidate = value?.message ?? value ?? "unknown error";
23
+ return typeof candidate === "string" ? candidate : String(candidate);
24
+ } catch {
25
+ return "unknown error";
26
+ }
27
+ }
28
+
29
+ function normalizeDiagnosticText(value) {
30
+ return diagnosticSource(value)
31
+ .toWellFormed()
32
+ .normalize("NFKC")
33
+ .replace(DISPLAY_WHITESPACE, " ")
34
+ .replace(UNSAFE_FOR_DISPLAY, "")
11
35
  .replace(/\s+/g, " ")
12
- .replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]")
13
- .replace(
14
- /\b(api[_-]?key|authorization|password|secret|token)\b\s*[:=]\s*["']?[^\s,;"']+/gi,
15
- "$1=[REDACTED]",
16
- )
17
- .slice(0, limit);
36
+ .trim();
37
+ }
38
+
39
+ function sanitizeDisplayText(value, limit = 400) {
40
+ if (typeof value !== "string" || limit <= 0) return "";
41
+ const escaped = value.replace(MARKDOWN_DELIMITERS, "\\$1");
42
+ const codePoints = [...escaped];
43
+ if (codePoints.length <= limit) return escaped;
44
+ if (limit === 1) return "…";
45
+ return `${codePoints.slice(0, limit - 1).join("")}…`;
46
+ }
47
+
48
+ function safeDiagnostic(value, limit = 400) {
49
+ const redacted = normalizeDiagnosticText(value)
50
+ .replace(AUTH_SCHEME, "$1 [REDACTED]")
51
+ .replace(SECRET_FIELD, "$1=[REDACTED]");
52
+ return sanitizeDisplayText(redacted, limit);
18
53
  }
19
54
 
20
55
  function positiveInteger(value, fallback, maximum) {