openclaw-safeclaw-plugin 1.0.0 → 1.1.0
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 +9 -7
- package/cli.tsx +116 -26
- package/dist/cli.js +120 -26
- package/dist/index.js +88 -55
- package/dist/tui/About.js +1 -1
- package/dist/tui/App.js +1 -1
- package/dist/tui/Settings.js +25 -6
- package/dist/tui/Status.js +94 -2
- package/dist/tui/config.d.ts +4 -0
- package/dist/tui/config.js +42 -3
- package/index.ts +89 -55
- package/package.json +2 -2
- package/tui/About.tsx +21 -4
- package/tui/App.tsx +1 -1
- package/tui/Settings.tsx +31 -7
- package/tui/Status.tsx +128 -2
- package/tui/config.ts +42 -2
package/tui/config.ts
CHANGED
|
@@ -32,7 +32,7 @@ export const CONFIG_PATH = join(homedir(), '.safeclaw', 'config.json');
|
|
|
32
32
|
|
|
33
33
|
export function loadConfig(): SafeClawConfig {
|
|
34
34
|
const defaults: SafeClawConfig = {
|
|
35
|
-
serviceUrl: '
|
|
35
|
+
serviceUrl: 'http://localhost:8420/api/v1',
|
|
36
36
|
apiKey: '',
|
|
37
37
|
timeoutMs: 5000,
|
|
38
38
|
enabled: true,
|
|
@@ -57,12 +57,21 @@ export function loadConfig(): SafeClawConfig {
|
|
|
57
57
|
} catch {
|
|
58
58
|
// Config file unreadable — use defaults
|
|
59
59
|
}
|
|
60
|
+
} else {
|
|
61
|
+
console.warn(`[SafeClaw] No config file found at ${CONFIG_PATH} — using defaults (serviceUrl=${defaults.serviceUrl})`);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
// Env vars override config file
|
|
63
65
|
if (process.env.SAFECLAW_URL) defaults.serviceUrl = process.env.SAFECLAW_URL;
|
|
64
66
|
if (process.env.SAFECLAW_API_KEY) defaults.apiKey = process.env.SAFECLAW_API_KEY;
|
|
65
|
-
if (process.env.SAFECLAW_TIMEOUT_MS)
|
|
67
|
+
if (process.env.SAFECLAW_TIMEOUT_MS) {
|
|
68
|
+
const parsed = parseInt(process.env.SAFECLAW_TIMEOUT_MS, 10);
|
|
69
|
+
if (!Number.isNaN(parsed) && parsed > 0) {
|
|
70
|
+
defaults.timeoutMs = parsed;
|
|
71
|
+
} else {
|
|
72
|
+
console.warn(`[SafeClaw] Invalid SAFECLAW_TIMEOUT_MS="${process.env.SAFECLAW_TIMEOUT_MS}", using default ${defaults.timeoutMs}ms`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
66
75
|
if (process.env.SAFECLAW_ENABLED === 'false') defaults.enabled = false;
|
|
67
76
|
if (process.env.SAFECLAW_ENFORCEMENT) defaults.enforcement = process.env.SAFECLAW_ENFORCEMENT as SafeClawConfig['enforcement'];
|
|
68
77
|
if (process.env.SAFECLAW_FAIL_MODE) defaults.failMode = process.env.SAFECLAW_FAIL_MODE as SafeClawConfig['failMode'];
|
|
@@ -86,6 +95,19 @@ export function loadConfig(): SafeClawConfig {
|
|
|
86
95
|
return defaults;
|
|
87
96
|
}
|
|
88
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Check whether a URL is a valid http:// or https:// URL.
|
|
100
|
+
*/
|
|
101
|
+
export function isValidServiceUrl(url: string): boolean {
|
|
102
|
+
if (!url || url.trim() === '') return false;
|
|
103
|
+
try {
|
|
104
|
+
const parsed = new URL(url);
|
|
105
|
+
return parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
89
111
|
/**
|
|
90
112
|
* Persist managed config fields back to ~/.safeclaw/config.json.
|
|
91
113
|
* Reads the existing file (if any), merges the fields SafeClaw manages,
|
|
@@ -101,6 +123,14 @@ export function saveConfig(config: SafeClawConfig): void {
|
|
|
101
123
|
}
|
|
102
124
|
}
|
|
103
125
|
|
|
126
|
+
// Normalize serviceUrl: strip trailing slashes (consistent with loadConfig)
|
|
127
|
+
config.serviceUrl = config.serviceUrl.replace(/\/+$/, '');
|
|
128
|
+
|
|
129
|
+
// Validate serviceUrl before saving
|
|
130
|
+
if (!isValidServiceUrl(config.serviceUrl)) {
|
|
131
|
+
throw new Error(`Invalid service URL: "${config.serviceUrl}" — must be a valid http:// or https:// URL`);
|
|
132
|
+
}
|
|
133
|
+
|
|
104
134
|
// Merge managed fields into existing structure
|
|
105
135
|
existing.enabled = config.enabled;
|
|
106
136
|
|
|
@@ -108,6 +138,9 @@ export function saveConfig(config: SafeClawConfig): void {
|
|
|
108
138
|
existing.remote = {};
|
|
109
139
|
}
|
|
110
140
|
(existing.remote as Record<string, unknown>).serviceUrl = config.serviceUrl;
|
|
141
|
+
if (config.apiKey) {
|
|
142
|
+
(existing.remote as Record<string, unknown>).apiKey = config.apiKey;
|
|
143
|
+
}
|
|
111
144
|
|
|
112
145
|
if (!existing.enforcement || typeof existing.enforcement !== 'object') {
|
|
113
146
|
existing.enforcement = {};
|
|
@@ -115,6 +148,13 @@ export function saveConfig(config: SafeClawConfig): void {
|
|
|
115
148
|
(existing.enforcement as Record<string, unknown>).mode = config.enforcement;
|
|
116
149
|
(existing.enforcement as Record<string, unknown>).failMode = config.failMode;
|
|
117
150
|
|
|
151
|
+
if (config.agentId) {
|
|
152
|
+
existing.agentId = config.agentId;
|
|
153
|
+
}
|
|
154
|
+
if (config.agentToken) {
|
|
155
|
+
existing.agentToken = config.agentToken;
|
|
156
|
+
}
|
|
157
|
+
|
|
118
158
|
// Ensure parent directory exists
|
|
119
159
|
mkdirSync(dirname(CONFIG_PATH), { recursive: true, mode: 0o700 });
|
|
120
160
|
|