@43world/llm-logger-openclaw-plugin 0.0.3

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.
@@ -0,0 +1,52 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ function isOpenClawRoot(dir: string): boolean {
5
+ const packageJsonPath = path.join(dir, "package.json");
6
+ if (!fs.existsSync(packageJsonPath)) {
7
+ return false;
8
+ }
9
+
10
+ try {
11
+ const parsed = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")) as {
12
+ name?: unknown;
13
+ };
14
+ return parsed.name === "openclaw";
15
+ } catch {
16
+ return false;
17
+ }
18
+ }
19
+
20
+ function walkUp(startPath: string): string | null {
21
+ let current = fs.existsSync(startPath) && fs.statSync(startPath).isFile() ? path.dirname(startPath) : startPath;
22
+
23
+ while (true) {
24
+ if (isOpenClawRoot(current)) {
25
+ return current;
26
+ }
27
+ const parent = path.dirname(current);
28
+ if (parent === current) {
29
+ return null;
30
+ }
31
+ current = parent;
32
+ }
33
+ }
34
+
35
+ export function resolveOpenClawRoot(params: {
36
+ workspaceDir?: string;
37
+ } = {}): string {
38
+ const candidates = [
39
+ process.argv[1],
40
+ params.workspaceDir,
41
+ process.cwd(),
42
+ ].filter((entry): entry is string => typeof entry === "string" && entry.trim().length > 0);
43
+
44
+ for (const candidate of candidates) {
45
+ const resolved = walkUp(candidate);
46
+ if (resolved) {
47
+ return resolved;
48
+ }
49
+ }
50
+
51
+ throw new Error("unable to resolve openclaw package root from process context");
52
+ }
@@ -0,0 +1,57 @@
1
+ const SENSITIVE_KEYS = new Set([
2
+ "authorization",
3
+ "proxy-authorization",
4
+ "api-key",
5
+ "x-api-key",
6
+ "apikey",
7
+ "apiKey",
8
+ "token",
9
+ "access_token",
10
+ "refresh_token",
11
+ "secret",
12
+ "password",
13
+ ]);
14
+
15
+ export function redactHeaders(
16
+ headers: Record<string, string>,
17
+ redactAuthorization: boolean,
18
+ ): Record<string, string> {
19
+ if (!redactAuthorization) {
20
+ return { ...headers };
21
+ }
22
+
23
+ const next: Record<string, string> = {};
24
+ for (const [key, value] of Object.entries(headers)) {
25
+ next[key] = SENSITIVE_KEYS.has(key.toLowerCase()) ? "[REDACTED]" : value;
26
+ }
27
+ return next;
28
+ }
29
+
30
+ function redactString(value: string, redactAuthorization: boolean): string {
31
+ if (!redactAuthorization) {
32
+ return value;
33
+ }
34
+ if (/^Bearer\s+/i.test(value)) {
35
+ return "[REDACTED]";
36
+ }
37
+ return value;
38
+ }
39
+
40
+ export function redactValue(value: unknown, redactAuthorization: boolean): unknown {
41
+ if (Array.isArray(value)) {
42
+ return value.map((entry) => redactValue(entry, redactAuthorization));
43
+ }
44
+
45
+ if (!value || typeof value !== "object") {
46
+ return typeof value === "string" ? redactString(value, redactAuthorization) : value;
47
+ }
48
+
49
+ const record = value as Record<string, unknown>;
50
+ const next: Record<string, unknown> = {};
51
+ for (const [key, entry] of Object.entries(record)) {
52
+ next[key] = SENSITIVE_KEYS.has(key.toLowerCase())
53
+ ? "[REDACTED]"
54
+ : redactValue(entry, redactAuthorization);
55
+ }
56
+ return next;
57
+ }