fastgrc-openclaw 1.0.28 → 1.0.30
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/bin.js +151 -20
- package/dist/bin.mjs +151 -20
- package/dist/plugin.d.mts +9 -1
- package/dist/plugin.d.ts +9 -1
- package/dist/plugin.js +93 -25
- package/dist/plugin.mjs +90 -25
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -24,9 +24,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/bin.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
29
|
-
var
|
|
27
|
+
var fs3 = __toESM(require("fs"));
|
|
28
|
+
var os3 = __toESM(require("os"));
|
|
29
|
+
var path3 = __toESM(require("path"));
|
|
30
30
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
var fs = __toESM(require("fs"));
|
|
@@ -93,21 +93,107 @@ args: ${JSON.stringify(args)}`;
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
// src/plugin.ts
|
|
97
|
+
var net = __toESM(require("net"));
|
|
98
|
+
var fs2 = __toESM(require("fs"));
|
|
99
|
+
var os2 = __toESM(require("os"));
|
|
100
|
+
var path2 = __toESM(require("path"));
|
|
101
|
+
function readExecApprovalsConfig() {
|
|
102
|
+
const cfgPath = path2.join(os2.homedir(), ".openclaw", "exec-approvals.json");
|
|
103
|
+
try {
|
|
104
|
+
return JSON.parse(fs2.readFileSync(cfgPath, "utf8"));
|
|
105
|
+
} catch {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function startExecApprovalsServer(apiKey, policyId, baseUrl) {
|
|
110
|
+
const cfg = readExecApprovalsConfig();
|
|
111
|
+
if (!cfg?.socket?.path || !cfg?.socket?.token) {
|
|
112
|
+
console.warn("[fastgrc] exec-approvals: no socket config found \u2014 webchat execs will not be evaluated");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const { path: sockPath, token: configToken } = cfg.socket;
|
|
116
|
+
try {
|
|
117
|
+
fs2.unlinkSync(sockPath);
|
|
118
|
+
} catch {
|
|
119
|
+
}
|
|
120
|
+
const server = net.createServer((conn) => {
|
|
121
|
+
let buffer = "";
|
|
122
|
+
conn.on("data", (chunk) => {
|
|
123
|
+
buffer += chunk.toString("utf8");
|
|
124
|
+
const idx = buffer.indexOf("\n");
|
|
125
|
+
if (idx === -1) return;
|
|
126
|
+
const line = buffer.slice(0, idx).trim();
|
|
127
|
+
buffer = "";
|
|
128
|
+
if (!line) {
|
|
129
|
+
conn.destroy();
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
let msg;
|
|
133
|
+
try {
|
|
134
|
+
msg = JSON.parse(line);
|
|
135
|
+
} catch {
|
|
136
|
+
conn.destroy();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (msg.type !== "request" || msg.token !== configToken) {
|
|
140
|
+
conn.destroy();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const req = msg.request ?? {};
|
|
144
|
+
const command = String(req.command ?? req.commandPreview ?? "unknown");
|
|
145
|
+
const agentId = req.agentId || void 0;
|
|
146
|
+
evaluate({
|
|
147
|
+
toolName: "Exec",
|
|
148
|
+
args: { command, cwd: req.cwd },
|
|
149
|
+
agentId,
|
|
150
|
+
apiKey,
|
|
151
|
+
policyId,
|
|
152
|
+
baseUrl
|
|
153
|
+
}).then((result) => {
|
|
154
|
+
let decision = "allow-once";
|
|
155
|
+
if (result && (result.decision === "block" || result.decision === "require_approval")) {
|
|
156
|
+
decision = "deny";
|
|
157
|
+
const rule = result.policyContext?.matchedRule;
|
|
158
|
+
console.warn(rule ? `[fastgrc] exec blocked: [${rule}] ${result.reasoning}` : `[fastgrc] exec blocked: ${result.reasoning}`);
|
|
159
|
+
}
|
|
160
|
+
conn.write(JSON.stringify({ type: "decision", decision }) + "\n");
|
|
161
|
+
conn.destroy();
|
|
162
|
+
}).catch(() => {
|
|
163
|
+
conn.write(JSON.stringify({ type: "decision", decision: "allow-once" }) + "\n");
|
|
164
|
+
conn.destroy();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
conn.on("error", () => {
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
server.listen(sockPath, () => {
|
|
171
|
+
try {
|
|
172
|
+
fs2.chmodSync(sockPath, 384);
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
console.log(`[fastgrc] exec-approvals server listening on ${sockPath}`);
|
|
176
|
+
});
|
|
177
|
+
server.on("error", (err) => {
|
|
178
|
+
console.warn(`[fastgrc] exec-approvals server error: ${err.message}`);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
96
182
|
// src/bin.ts
|
|
97
|
-
var CONFIG_PATH =
|
|
183
|
+
var CONFIG_PATH = path3.join(os3.homedir(), ".fastgrc.json");
|
|
98
184
|
function readConfig() {
|
|
99
185
|
try {
|
|
100
|
-
return JSON.parse(
|
|
186
|
+
return JSON.parse(fs3.readFileSync(CONFIG_PATH, "utf8"));
|
|
101
187
|
} catch {
|
|
102
188
|
return {};
|
|
103
189
|
}
|
|
104
190
|
}
|
|
105
191
|
function writeConfig(data) {
|
|
106
|
-
|
|
192
|
+
fs3.writeFileSync(CONFIG_PATH, JSON.stringify(data, null, 2), { mode: 384 });
|
|
107
193
|
}
|
|
108
194
|
function computeHandler() {
|
|
109
195
|
const binPath = process.argv[1];
|
|
110
|
-
const homeDir =
|
|
196
|
+
const homeDir = os3.homedir();
|
|
111
197
|
return { binPath, homeDir, handlerStr: `HOME=${homeDir} node ${binPath}` };
|
|
112
198
|
}
|
|
113
199
|
function printTestSnippet(handlerStr) {
|
|
@@ -121,7 +207,7 @@ Test it directly (bypasses OpenClaw):
|
|
|
121
207
|
);
|
|
122
208
|
}
|
|
123
209
|
function doInstallHook(targetDir) {
|
|
124
|
-
const hookMdPath =
|
|
210
|
+
const hookMdPath = path3.join(targetDir, "HOOK.md");
|
|
125
211
|
const { handlerStr } = computeHandler();
|
|
126
212
|
const HOOK_ENTRY = ` - matcher: PreToolUse
|
|
127
213
|
handler: "${handlerStr}"
|
|
@@ -131,8 +217,8 @@ function doInstallHook(targetDir) {
|
|
|
131
217
|
if (!hasKey) {
|
|
132
218
|
process.stdout.write("\u26A0 No API key set yet. Run: fastgrc-hook set-key fgrc_k1_your_key\n\n");
|
|
133
219
|
}
|
|
134
|
-
if (!
|
|
135
|
-
|
|
220
|
+
if (!fs3.existsSync(hookMdPath)) {
|
|
221
|
+
fs3.writeFileSync(hookMdPath, HOOK_BLOCK, "utf8");
|
|
136
222
|
process.stdout.write(`\u2713 Created ${hookMdPath}
|
|
137
223
|
Handler: ${handlerStr}
|
|
138
224
|
|
|
@@ -141,7 +227,7 @@ Restart OpenClaw \u2014 FastGRC will evaluate every tool call.
|
|
|
141
227
|
printTestSnippet(handlerStr);
|
|
142
228
|
return;
|
|
143
229
|
}
|
|
144
|
-
const existing =
|
|
230
|
+
const existing = fs3.readFileSync(hookMdPath, "utf8");
|
|
145
231
|
if (existing.includes(handlerStr)) {
|
|
146
232
|
process.stdout.write(`\u2713 FastGRC hook already up to date in ${hookMdPath}
|
|
147
233
|
Handler: ${handlerStr}
|
|
@@ -154,7 +240,7 @@ Restart OpenClaw \u2014 FastGRC will evaluate every tool call.
|
|
|
154
240
|
/handler:\s*"[^"]*(?:fastgrc-hook|fastgrc-openclaw)[^"]*"/,
|
|
155
241
|
`handler: "${handlerStr}"`
|
|
156
242
|
);
|
|
157
|
-
|
|
243
|
+
fs3.writeFileSync(hookMdPath, patched, "utf8");
|
|
158
244
|
process.stdout.write(`\u2713 Updated handler in ${hookMdPath} \u2014 now uses absolute path.
|
|
159
245
|
Handler: ${handlerStr}
|
|
160
246
|
|
|
@@ -173,7 +259,7 @@ ${HOOK_ENTRY}`;
|
|
|
173
259
|
} else {
|
|
174
260
|
updated = HOOK_BLOCK + "\n" + existing;
|
|
175
261
|
}
|
|
176
|
-
|
|
262
|
+
fs3.writeFileSync(hookMdPath, updated, "utf8");
|
|
177
263
|
process.stdout.write(`\u2713 Updated ${hookMdPath} \u2014 FastGRC hook added.
|
|
178
264
|
Handler: ${handlerStr}
|
|
179
265
|
|
|
@@ -182,12 +268,12 @@ Restart OpenClaw to activate.
|
|
|
182
268
|
printTestSnippet(handlerStr);
|
|
183
269
|
}
|
|
184
270
|
function doUninstallHook(targetDir) {
|
|
185
|
-
const hookMdPath =
|
|
186
|
-
if (!
|
|
271
|
+
const hookMdPath = path3.join(targetDir, "HOOK.md");
|
|
272
|
+
if (!fs3.existsSync(hookMdPath)) {
|
|
187
273
|
process.stdout.write("No HOOK.md found \u2014 nothing to remove.\n");
|
|
188
274
|
return;
|
|
189
275
|
}
|
|
190
|
-
const existing =
|
|
276
|
+
const existing = fs3.readFileSync(hookMdPath, "utf8");
|
|
191
277
|
const patched = existing.replace(
|
|
192
278
|
/[ \t]*-[ \t]*matcher:[ \t]*PreToolUse\n[ \t]*handler:[ \t]*"[^"]*(?:fastgrc-hook|fastgrc-openclaw)[^"]*"\n?/,
|
|
193
279
|
""
|
|
@@ -195,11 +281,36 @@ function doUninstallHook(targetDir) {
|
|
|
195
281
|
if (patched === existing) {
|
|
196
282
|
process.stdout.write("FastGRC hook not found in HOOK.md \u2014 nothing to remove.\n");
|
|
197
283
|
} else {
|
|
198
|
-
|
|
284
|
+
fs3.writeFileSync(hookMdPath, patched, "utf8");
|
|
199
285
|
process.stdout.write(`\u2713 FastGRC hook removed from ${hookMdPath}
|
|
200
286
|
`);
|
|
201
287
|
}
|
|
202
288
|
}
|
|
289
|
+
function doConfigureExecApprovals() {
|
|
290
|
+
const cfgPath = path3.join(os3.homedir(), ".openclaw", "exec-approvals.json");
|
|
291
|
+
if (!fs3.existsSync(cfgPath)) {
|
|
292
|
+
process.stdout.write(`\u26A0 ${cfgPath} not found \u2014 skipping exec-approvals config (OpenClaw may not be installed here).
|
|
293
|
+
`);
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
let existing = {};
|
|
297
|
+
try {
|
|
298
|
+
existing = JSON.parse(fs3.readFileSync(cfgPath, "utf8"));
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
const updated = {
|
|
302
|
+
...existing,
|
|
303
|
+
defaults: {
|
|
304
|
+
security: "deny",
|
|
305
|
+
ask: "always",
|
|
306
|
+
askFallback: "deny",
|
|
307
|
+
autoAllowSkills: false
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
fs3.writeFileSync(cfgPath, JSON.stringify(updated, null, 2), "utf8");
|
|
311
|
+
process.stdout.write(`\u2713 exec-approvals.json configured \u2014 all webchat execs routed through FastGRC.
|
|
312
|
+
`);
|
|
313
|
+
}
|
|
203
314
|
var [, , cmd, arg] = process.argv;
|
|
204
315
|
if (cmd === "set-key") {
|
|
205
316
|
if (!arg) {
|
|
@@ -294,10 +405,30 @@ if (cmd === "setup") {
|
|
|
294
405
|
process.stdout.write(" (no policy ID \u2014 org-wide default will be used)\n");
|
|
295
406
|
}
|
|
296
407
|
doInstallHook(process.cwd());
|
|
297
|
-
|
|
298
|
-
process.stdout.write(
|
|
408
|
+
doConfigureExecApprovals();
|
|
409
|
+
process.stdout.write("\n\u2713 Config, HOOK.md, and exec-approvals done.\n");
|
|
410
|
+
process.stdout.write('Restart OpenClaw, then run "fastgrc-hook test" to verify.\n');
|
|
299
411
|
process.exit(0);
|
|
300
412
|
}
|
|
413
|
+
if (cmd === "serve-approvals") {
|
|
414
|
+
const apiKey = resolveApiKey();
|
|
415
|
+
if (!apiKey) {
|
|
416
|
+
process.stderr.write("No API key configured. Run: fastgrc-hook set-key fgrc_k1_...\n");
|
|
417
|
+
process.exit(1);
|
|
418
|
+
}
|
|
419
|
+
const cfg = readExecApprovalsConfig();
|
|
420
|
+
if (!cfg?.socket?.path || !cfg?.socket?.token) {
|
|
421
|
+
process.stderr.write(
|
|
422
|
+
'No exec-approvals socket configured.\nRun "fastgrc-hook setup" to configure OpenClaw exec-approvals, then restart OpenClaw.\n'
|
|
423
|
+
);
|
|
424
|
+
process.exit(1);
|
|
425
|
+
}
|
|
426
|
+
const policyId = process.env.FASTGRC_POLICY_ID ?? readConfig().policyId;
|
|
427
|
+
const baseUrl = process.env.FASTGRC_BASE_URL ?? "https://app.fastgrc.ai";
|
|
428
|
+
process.stdout.write(`[fastgrc] serve-approvals running \u2014 listening on ${cfg.socket.path}
|
|
429
|
+
`);
|
|
430
|
+
startExecApprovalsServer(apiKey, policyId, baseUrl);
|
|
431
|
+
}
|
|
301
432
|
if (cmd === "uninstall") {
|
|
302
433
|
const targetDir = arg || process.cwd();
|
|
303
434
|
const cfg = readConfig();
|
|
@@ -364,7 +495,7 @@ if (cmd === "test") {
|
|
|
364
495
|
`);
|
|
365
496
|
process.exit(0);
|
|
366
497
|
}
|
|
367
|
-
if (cmd === "test" || cmd === "where" || cmd === "which-hook" || cmd === "setup" || cmd === "uninstall" || cmd === "install-hook" || cmd === "uninstall-hook") {
|
|
498
|
+
if (cmd === "test" || cmd === "where" || cmd === "which-hook" || cmd === "setup" || cmd === "uninstall" || cmd === "install-hook" || cmd === "uninstall-hook" || cmd === "serve-approvals") {
|
|
368
499
|
} else {
|
|
369
500
|
const apiKey = resolveApiKey();
|
|
370
501
|
if (!apiKey) {
|
package/dist/bin.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/bin.ts
|
|
4
|
-
import * as
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
4
|
+
import * as fs3 from "fs";
|
|
5
|
+
import * as os3 from "os";
|
|
6
|
+
import * as path3 from "path";
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
9
|
import * as fs from "fs";
|
|
@@ -70,21 +70,107 @@ args: ${JSON.stringify(args)}`;
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// src/plugin.ts
|
|
74
|
+
import * as net from "net";
|
|
75
|
+
import * as fs2 from "fs";
|
|
76
|
+
import * as os2 from "os";
|
|
77
|
+
import * as path2 from "path";
|
|
78
|
+
function readExecApprovalsConfig() {
|
|
79
|
+
const cfgPath = path2.join(os2.homedir(), ".openclaw", "exec-approvals.json");
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(fs2.readFileSync(cfgPath, "utf8"));
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function startExecApprovalsServer(apiKey, policyId, baseUrl) {
|
|
87
|
+
const cfg = readExecApprovalsConfig();
|
|
88
|
+
if (!cfg?.socket?.path || !cfg?.socket?.token) {
|
|
89
|
+
console.warn("[fastgrc] exec-approvals: no socket config found \u2014 webchat execs will not be evaluated");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const { path: sockPath, token: configToken } = cfg.socket;
|
|
93
|
+
try {
|
|
94
|
+
fs2.unlinkSync(sockPath);
|
|
95
|
+
} catch {
|
|
96
|
+
}
|
|
97
|
+
const server = net.createServer((conn) => {
|
|
98
|
+
let buffer = "";
|
|
99
|
+
conn.on("data", (chunk) => {
|
|
100
|
+
buffer += chunk.toString("utf8");
|
|
101
|
+
const idx = buffer.indexOf("\n");
|
|
102
|
+
if (idx === -1) return;
|
|
103
|
+
const line = buffer.slice(0, idx).trim();
|
|
104
|
+
buffer = "";
|
|
105
|
+
if (!line) {
|
|
106
|
+
conn.destroy();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
let msg;
|
|
110
|
+
try {
|
|
111
|
+
msg = JSON.parse(line);
|
|
112
|
+
} catch {
|
|
113
|
+
conn.destroy();
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (msg.type !== "request" || msg.token !== configToken) {
|
|
117
|
+
conn.destroy();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const req = msg.request ?? {};
|
|
121
|
+
const command = String(req.command ?? req.commandPreview ?? "unknown");
|
|
122
|
+
const agentId = req.agentId || void 0;
|
|
123
|
+
evaluate({
|
|
124
|
+
toolName: "Exec",
|
|
125
|
+
args: { command, cwd: req.cwd },
|
|
126
|
+
agentId,
|
|
127
|
+
apiKey,
|
|
128
|
+
policyId,
|
|
129
|
+
baseUrl
|
|
130
|
+
}).then((result) => {
|
|
131
|
+
let decision = "allow-once";
|
|
132
|
+
if (result && (result.decision === "block" || result.decision === "require_approval")) {
|
|
133
|
+
decision = "deny";
|
|
134
|
+
const rule = result.policyContext?.matchedRule;
|
|
135
|
+
console.warn(rule ? `[fastgrc] exec blocked: [${rule}] ${result.reasoning}` : `[fastgrc] exec blocked: ${result.reasoning}`);
|
|
136
|
+
}
|
|
137
|
+
conn.write(JSON.stringify({ type: "decision", decision }) + "\n");
|
|
138
|
+
conn.destroy();
|
|
139
|
+
}).catch(() => {
|
|
140
|
+
conn.write(JSON.stringify({ type: "decision", decision: "allow-once" }) + "\n");
|
|
141
|
+
conn.destroy();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
conn.on("error", () => {
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
server.listen(sockPath, () => {
|
|
148
|
+
try {
|
|
149
|
+
fs2.chmodSync(sockPath, 384);
|
|
150
|
+
} catch {
|
|
151
|
+
}
|
|
152
|
+
console.log(`[fastgrc] exec-approvals server listening on ${sockPath}`);
|
|
153
|
+
});
|
|
154
|
+
server.on("error", (err) => {
|
|
155
|
+
console.warn(`[fastgrc] exec-approvals server error: ${err.message}`);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
73
159
|
// src/bin.ts
|
|
74
|
-
var CONFIG_PATH =
|
|
160
|
+
var CONFIG_PATH = path3.join(os3.homedir(), ".fastgrc.json");
|
|
75
161
|
function readConfig() {
|
|
76
162
|
try {
|
|
77
|
-
return JSON.parse(
|
|
163
|
+
return JSON.parse(fs3.readFileSync(CONFIG_PATH, "utf8"));
|
|
78
164
|
} catch {
|
|
79
165
|
return {};
|
|
80
166
|
}
|
|
81
167
|
}
|
|
82
168
|
function writeConfig(data) {
|
|
83
|
-
|
|
169
|
+
fs3.writeFileSync(CONFIG_PATH, JSON.stringify(data, null, 2), { mode: 384 });
|
|
84
170
|
}
|
|
85
171
|
function computeHandler() {
|
|
86
172
|
const binPath = process.argv[1];
|
|
87
|
-
const homeDir =
|
|
173
|
+
const homeDir = os3.homedir();
|
|
88
174
|
return { binPath, homeDir, handlerStr: `HOME=${homeDir} node ${binPath}` };
|
|
89
175
|
}
|
|
90
176
|
function printTestSnippet(handlerStr) {
|
|
@@ -98,7 +184,7 @@ Test it directly (bypasses OpenClaw):
|
|
|
98
184
|
);
|
|
99
185
|
}
|
|
100
186
|
function doInstallHook(targetDir) {
|
|
101
|
-
const hookMdPath =
|
|
187
|
+
const hookMdPath = path3.join(targetDir, "HOOK.md");
|
|
102
188
|
const { handlerStr } = computeHandler();
|
|
103
189
|
const HOOK_ENTRY = ` - matcher: PreToolUse
|
|
104
190
|
handler: "${handlerStr}"
|
|
@@ -108,8 +194,8 @@ function doInstallHook(targetDir) {
|
|
|
108
194
|
if (!hasKey) {
|
|
109
195
|
process.stdout.write("\u26A0 No API key set yet. Run: fastgrc-hook set-key fgrc_k1_your_key\n\n");
|
|
110
196
|
}
|
|
111
|
-
if (!
|
|
112
|
-
|
|
197
|
+
if (!fs3.existsSync(hookMdPath)) {
|
|
198
|
+
fs3.writeFileSync(hookMdPath, HOOK_BLOCK, "utf8");
|
|
113
199
|
process.stdout.write(`\u2713 Created ${hookMdPath}
|
|
114
200
|
Handler: ${handlerStr}
|
|
115
201
|
|
|
@@ -118,7 +204,7 @@ Restart OpenClaw \u2014 FastGRC will evaluate every tool call.
|
|
|
118
204
|
printTestSnippet(handlerStr);
|
|
119
205
|
return;
|
|
120
206
|
}
|
|
121
|
-
const existing =
|
|
207
|
+
const existing = fs3.readFileSync(hookMdPath, "utf8");
|
|
122
208
|
if (existing.includes(handlerStr)) {
|
|
123
209
|
process.stdout.write(`\u2713 FastGRC hook already up to date in ${hookMdPath}
|
|
124
210
|
Handler: ${handlerStr}
|
|
@@ -131,7 +217,7 @@ Restart OpenClaw \u2014 FastGRC will evaluate every tool call.
|
|
|
131
217
|
/handler:\s*"[^"]*(?:fastgrc-hook|fastgrc-openclaw)[^"]*"/,
|
|
132
218
|
`handler: "${handlerStr}"`
|
|
133
219
|
);
|
|
134
|
-
|
|
220
|
+
fs3.writeFileSync(hookMdPath, patched, "utf8");
|
|
135
221
|
process.stdout.write(`\u2713 Updated handler in ${hookMdPath} \u2014 now uses absolute path.
|
|
136
222
|
Handler: ${handlerStr}
|
|
137
223
|
|
|
@@ -150,7 +236,7 @@ ${HOOK_ENTRY}`;
|
|
|
150
236
|
} else {
|
|
151
237
|
updated = HOOK_BLOCK + "\n" + existing;
|
|
152
238
|
}
|
|
153
|
-
|
|
239
|
+
fs3.writeFileSync(hookMdPath, updated, "utf8");
|
|
154
240
|
process.stdout.write(`\u2713 Updated ${hookMdPath} \u2014 FastGRC hook added.
|
|
155
241
|
Handler: ${handlerStr}
|
|
156
242
|
|
|
@@ -159,12 +245,12 @@ Restart OpenClaw to activate.
|
|
|
159
245
|
printTestSnippet(handlerStr);
|
|
160
246
|
}
|
|
161
247
|
function doUninstallHook(targetDir) {
|
|
162
|
-
const hookMdPath =
|
|
163
|
-
if (!
|
|
248
|
+
const hookMdPath = path3.join(targetDir, "HOOK.md");
|
|
249
|
+
if (!fs3.existsSync(hookMdPath)) {
|
|
164
250
|
process.stdout.write("No HOOK.md found \u2014 nothing to remove.\n");
|
|
165
251
|
return;
|
|
166
252
|
}
|
|
167
|
-
const existing =
|
|
253
|
+
const existing = fs3.readFileSync(hookMdPath, "utf8");
|
|
168
254
|
const patched = existing.replace(
|
|
169
255
|
/[ \t]*-[ \t]*matcher:[ \t]*PreToolUse\n[ \t]*handler:[ \t]*"[^"]*(?:fastgrc-hook|fastgrc-openclaw)[^"]*"\n?/,
|
|
170
256
|
""
|
|
@@ -172,11 +258,36 @@ function doUninstallHook(targetDir) {
|
|
|
172
258
|
if (patched === existing) {
|
|
173
259
|
process.stdout.write("FastGRC hook not found in HOOK.md \u2014 nothing to remove.\n");
|
|
174
260
|
} else {
|
|
175
|
-
|
|
261
|
+
fs3.writeFileSync(hookMdPath, patched, "utf8");
|
|
176
262
|
process.stdout.write(`\u2713 FastGRC hook removed from ${hookMdPath}
|
|
177
263
|
`);
|
|
178
264
|
}
|
|
179
265
|
}
|
|
266
|
+
function doConfigureExecApprovals() {
|
|
267
|
+
const cfgPath = path3.join(os3.homedir(), ".openclaw", "exec-approvals.json");
|
|
268
|
+
if (!fs3.existsSync(cfgPath)) {
|
|
269
|
+
process.stdout.write(`\u26A0 ${cfgPath} not found \u2014 skipping exec-approvals config (OpenClaw may not be installed here).
|
|
270
|
+
`);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
let existing = {};
|
|
274
|
+
try {
|
|
275
|
+
existing = JSON.parse(fs3.readFileSync(cfgPath, "utf8"));
|
|
276
|
+
} catch {
|
|
277
|
+
}
|
|
278
|
+
const updated = {
|
|
279
|
+
...existing,
|
|
280
|
+
defaults: {
|
|
281
|
+
security: "deny",
|
|
282
|
+
ask: "always",
|
|
283
|
+
askFallback: "deny",
|
|
284
|
+
autoAllowSkills: false
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
fs3.writeFileSync(cfgPath, JSON.stringify(updated, null, 2), "utf8");
|
|
288
|
+
process.stdout.write(`\u2713 exec-approvals.json configured \u2014 all webchat execs routed through FastGRC.
|
|
289
|
+
`);
|
|
290
|
+
}
|
|
180
291
|
var [, , cmd, arg] = process.argv;
|
|
181
292
|
if (cmd === "set-key") {
|
|
182
293
|
if (!arg) {
|
|
@@ -271,10 +382,30 @@ if (cmd === "setup") {
|
|
|
271
382
|
process.stdout.write(" (no policy ID \u2014 org-wide default will be used)\n");
|
|
272
383
|
}
|
|
273
384
|
doInstallHook(process.cwd());
|
|
274
|
-
|
|
275
|
-
process.stdout.write(
|
|
385
|
+
doConfigureExecApprovals();
|
|
386
|
+
process.stdout.write("\n\u2713 Config, HOOK.md, and exec-approvals done.\n");
|
|
387
|
+
process.stdout.write('Restart OpenClaw, then run "fastgrc-hook test" to verify.\n');
|
|
276
388
|
process.exit(0);
|
|
277
389
|
}
|
|
390
|
+
if (cmd === "serve-approvals") {
|
|
391
|
+
const apiKey = resolveApiKey();
|
|
392
|
+
if (!apiKey) {
|
|
393
|
+
process.stderr.write("No API key configured. Run: fastgrc-hook set-key fgrc_k1_...\n");
|
|
394
|
+
process.exit(1);
|
|
395
|
+
}
|
|
396
|
+
const cfg = readExecApprovalsConfig();
|
|
397
|
+
if (!cfg?.socket?.path || !cfg?.socket?.token) {
|
|
398
|
+
process.stderr.write(
|
|
399
|
+
'No exec-approvals socket configured.\nRun "fastgrc-hook setup" to configure OpenClaw exec-approvals, then restart OpenClaw.\n'
|
|
400
|
+
);
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
const policyId = process.env.FASTGRC_POLICY_ID ?? readConfig().policyId;
|
|
404
|
+
const baseUrl = process.env.FASTGRC_BASE_URL ?? "https://app.fastgrc.ai";
|
|
405
|
+
process.stdout.write(`[fastgrc] serve-approvals running \u2014 listening on ${cfg.socket.path}
|
|
406
|
+
`);
|
|
407
|
+
startExecApprovalsServer(apiKey, policyId, baseUrl);
|
|
408
|
+
}
|
|
278
409
|
if (cmd === "uninstall") {
|
|
279
410
|
const targetDir = arg || process.cwd();
|
|
280
411
|
const cfg = readConfig();
|
|
@@ -341,7 +472,7 @@ if (cmd === "test") {
|
|
|
341
472
|
`);
|
|
342
473
|
process.exit(0);
|
|
343
474
|
}
|
|
344
|
-
if (cmd === "test" || cmd === "where" || cmd === "which-hook" || cmd === "setup" || cmd === "uninstall" || cmd === "install-hook" || cmd === "uninstall-hook") {
|
|
475
|
+
if (cmd === "test" || cmd === "where" || cmd === "which-hook" || cmd === "setup" || cmd === "uninstall" || cmd === "install-hook" || cmd === "uninstall-hook" || cmd === "serve-approvals") {
|
|
345
476
|
} else {
|
|
346
477
|
const apiKey = resolveApiKey();
|
|
347
478
|
if (!apiKey) {
|
package/dist/plugin.d.mts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
interface ExecApprovalsConfig {
|
|
2
|
+
socket?: {
|
|
3
|
+
path?: string;
|
|
4
|
+
token?: string;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
declare function readExecApprovalsConfig(): ExecApprovalsConfig | null;
|
|
8
|
+
declare function startExecApprovalsServer(apiKey: string, policyId?: string, baseUrl?: string): void;
|
|
1
9
|
declare const pluginEntry: {
|
|
2
10
|
id: string;
|
|
3
11
|
name: string;
|
|
@@ -5,4 +13,4 @@ declare const pluginEntry: {
|
|
|
5
13
|
register(api: any): void;
|
|
6
14
|
};
|
|
7
15
|
|
|
8
|
-
export { pluginEntry as default };
|
|
16
|
+
export { pluginEntry as default, readExecApprovalsConfig, startExecApprovalsServer };
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
interface ExecApprovalsConfig {
|
|
2
|
+
socket?: {
|
|
3
|
+
path?: string;
|
|
4
|
+
token?: string;
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
declare function readExecApprovalsConfig(): ExecApprovalsConfig | null;
|
|
8
|
+
declare function startExecApprovalsServer(apiKey: string, policyId?: string, baseUrl?: string): void;
|
|
1
9
|
declare const pluginEntry: {
|
|
2
10
|
id: string;
|
|
3
11
|
name: string;
|
|
@@ -5,4 +13,4 @@ declare const pluginEntry: {
|
|
|
5
13
|
register(api: any): void;
|
|
6
14
|
};
|
|
7
15
|
|
|
8
|
-
export { pluginEntry as default };
|
|
16
|
+
export { pluginEntry as default, readExecApprovalsConfig, startExecApprovalsServer };
|
package/dist/plugin.js
CHANGED
|
@@ -30,9 +30,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/plugin.ts
|
|
31
31
|
var plugin_exports = {};
|
|
32
32
|
__export(plugin_exports, {
|
|
33
|
-
default: () => plugin_default
|
|
33
|
+
default: () => plugin_default,
|
|
34
|
+
readExecApprovalsConfig: () => readExecApprovalsConfig,
|
|
35
|
+
startExecApprovalsServer: () => startExecApprovalsServer
|
|
34
36
|
});
|
|
35
37
|
module.exports = __toCommonJS(plugin_exports);
|
|
38
|
+
var net = __toESM(require("net"));
|
|
39
|
+
var fs2 = __toESM(require("fs"));
|
|
40
|
+
var os2 = __toESM(require("os"));
|
|
41
|
+
var path2 = __toESM(require("path"));
|
|
36
42
|
|
|
37
43
|
// src/index.ts
|
|
38
44
|
var fs = __toESM(require("fs"));
|
|
@@ -114,6 +120,86 @@ args: ${JSON.stringify(args)}`;
|
|
|
114
120
|
// src/plugin.ts
|
|
115
121
|
var DEFAULT_BASE_URL2 = "https://app.fastgrc.ai";
|
|
116
122
|
var DEFAULT_TIMEOUT_MS2 = 3e3;
|
|
123
|
+
function readExecApprovalsConfig() {
|
|
124
|
+
const cfgPath = path2.join(os2.homedir(), ".openclaw", "exec-approvals.json");
|
|
125
|
+
try {
|
|
126
|
+
return JSON.parse(fs2.readFileSync(cfgPath, "utf8"));
|
|
127
|
+
} catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function startExecApprovalsServer(apiKey, policyId, baseUrl) {
|
|
132
|
+
const cfg = readExecApprovalsConfig();
|
|
133
|
+
if (!cfg?.socket?.path || !cfg?.socket?.token) {
|
|
134
|
+
console.warn("[fastgrc] exec-approvals: no socket config found \u2014 webchat execs will not be evaluated");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const { path: sockPath, token: configToken } = cfg.socket;
|
|
138
|
+
try {
|
|
139
|
+
fs2.unlinkSync(sockPath);
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
const server = net.createServer((conn) => {
|
|
143
|
+
let buffer = "";
|
|
144
|
+
conn.on("data", (chunk) => {
|
|
145
|
+
buffer += chunk.toString("utf8");
|
|
146
|
+
const idx = buffer.indexOf("\n");
|
|
147
|
+
if (idx === -1) return;
|
|
148
|
+
const line = buffer.slice(0, idx).trim();
|
|
149
|
+
buffer = "";
|
|
150
|
+
if (!line) {
|
|
151
|
+
conn.destroy();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
let msg;
|
|
155
|
+
try {
|
|
156
|
+
msg = JSON.parse(line);
|
|
157
|
+
} catch {
|
|
158
|
+
conn.destroy();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (msg.type !== "request" || msg.token !== configToken) {
|
|
162
|
+
conn.destroy();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const req = msg.request ?? {};
|
|
166
|
+
const command = String(req.command ?? req.commandPreview ?? "unknown");
|
|
167
|
+
const agentId = req.agentId || void 0;
|
|
168
|
+
evaluate({
|
|
169
|
+
toolName: "Exec",
|
|
170
|
+
args: { command, cwd: req.cwd },
|
|
171
|
+
agentId,
|
|
172
|
+
apiKey,
|
|
173
|
+
policyId,
|
|
174
|
+
baseUrl
|
|
175
|
+
}).then((result) => {
|
|
176
|
+
let decision = "allow-once";
|
|
177
|
+
if (result && (result.decision === "block" || result.decision === "require_approval")) {
|
|
178
|
+
decision = "deny";
|
|
179
|
+
const rule = result.policyContext?.matchedRule;
|
|
180
|
+
console.warn(rule ? `[fastgrc] exec blocked: [${rule}] ${result.reasoning}` : `[fastgrc] exec blocked: ${result.reasoning}`);
|
|
181
|
+
}
|
|
182
|
+
conn.write(JSON.stringify({ type: "decision", decision }) + "\n");
|
|
183
|
+
conn.destroy();
|
|
184
|
+
}).catch(() => {
|
|
185
|
+
conn.write(JSON.stringify({ type: "decision", decision: "allow-once" }) + "\n");
|
|
186
|
+
conn.destroy();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
conn.on("error", () => {
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
server.listen(sockPath, () => {
|
|
193
|
+
try {
|
|
194
|
+
fs2.chmodSync(sockPath, 384);
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
console.log(`[fastgrc] exec-approvals server listening on ${sockPath}`);
|
|
198
|
+
});
|
|
199
|
+
server.on("error", (err) => {
|
|
200
|
+
console.warn(`[fastgrc] exec-approvals server error: ${err.message}`);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
117
203
|
var pluginEntry = {
|
|
118
204
|
id: "fastgrc",
|
|
119
205
|
name: "FastGRC Policy Router",
|
|
@@ -128,31 +214,7 @@ var pluginEntry = {
|
|
|
128
214
|
return;
|
|
129
215
|
}
|
|
130
216
|
console.log("[fastgrc] Plugin registered \u2014 before_tool_call hook active");
|
|
131
|
-
const probeEvents = [
|
|
132
|
-
"exec",
|
|
133
|
-
"before_exec",
|
|
134
|
-
"shell",
|
|
135
|
-
"before_shell",
|
|
136
|
-
"command",
|
|
137
|
-
"before_command",
|
|
138
|
-
"run",
|
|
139
|
-
"before_run",
|
|
140
|
-
"tool_call",
|
|
141
|
-
"before_tool",
|
|
142
|
-
"action",
|
|
143
|
-
"before_action",
|
|
144
|
-
"request",
|
|
145
|
-
"before_request",
|
|
146
|
-
"call",
|
|
147
|
-
"before_call"
|
|
148
|
-
];
|
|
149
|
-
for (const evt of probeEvents) {
|
|
150
|
-
api.on(evt, (...args) => {
|
|
151
|
-
console.log(`[fastgrc:hit] ${evt}`, JSON.stringify(args[0])?.slice(0, 120));
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
217
|
api.on("before_tool_call", async (event, ctx) => {
|
|
155
|
-
console.log(`[fastgrc] before_tool_call fired: ${event.toolName}`);
|
|
156
218
|
const result = await evaluate({
|
|
157
219
|
toolName: event.toolName,
|
|
158
220
|
args: event.params,
|
|
@@ -182,7 +244,13 @@ var pluginEntry = {
|
|
|
182
244
|
}
|
|
183
245
|
return void 0;
|
|
184
246
|
});
|
|
247
|
+
startExecApprovalsServer(apiKey, policyId, DEFAULT_BASE_URL2);
|
|
185
248
|
}
|
|
186
249
|
};
|
|
187
250
|
var plugin_default = pluginEntry;
|
|
251
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
252
|
+
0 && (module.exports = {
|
|
253
|
+
readExecApprovalsConfig,
|
|
254
|
+
startExecApprovalsServer
|
|
255
|
+
});
|
|
188
256
|
module.exports = module.exports.default ?? module.exports;
|
package/dist/plugin.mjs
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// src/plugin.ts
|
|
2
|
+
import * as net from "net";
|
|
3
|
+
import * as fs2 from "fs";
|
|
4
|
+
import * as os2 from "os";
|
|
5
|
+
import * as path2 from "path";
|
|
6
|
+
|
|
1
7
|
// src/index.ts
|
|
2
8
|
import * as fs from "fs";
|
|
3
9
|
import * as os from "os";
|
|
@@ -78,6 +84,86 @@ args: ${JSON.stringify(args)}`;
|
|
|
78
84
|
// src/plugin.ts
|
|
79
85
|
var DEFAULT_BASE_URL2 = "https://app.fastgrc.ai";
|
|
80
86
|
var DEFAULT_TIMEOUT_MS2 = 3e3;
|
|
87
|
+
function readExecApprovalsConfig() {
|
|
88
|
+
const cfgPath = path2.join(os2.homedir(), ".openclaw", "exec-approvals.json");
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(fs2.readFileSync(cfgPath, "utf8"));
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function startExecApprovalsServer(apiKey, policyId, baseUrl) {
|
|
96
|
+
const cfg = readExecApprovalsConfig();
|
|
97
|
+
if (!cfg?.socket?.path || !cfg?.socket?.token) {
|
|
98
|
+
console.warn("[fastgrc] exec-approvals: no socket config found \u2014 webchat execs will not be evaluated");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const { path: sockPath, token: configToken } = cfg.socket;
|
|
102
|
+
try {
|
|
103
|
+
fs2.unlinkSync(sockPath);
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
const server = net.createServer((conn) => {
|
|
107
|
+
let buffer = "";
|
|
108
|
+
conn.on("data", (chunk) => {
|
|
109
|
+
buffer += chunk.toString("utf8");
|
|
110
|
+
const idx = buffer.indexOf("\n");
|
|
111
|
+
if (idx === -1) return;
|
|
112
|
+
const line = buffer.slice(0, idx).trim();
|
|
113
|
+
buffer = "";
|
|
114
|
+
if (!line) {
|
|
115
|
+
conn.destroy();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
let msg;
|
|
119
|
+
try {
|
|
120
|
+
msg = JSON.parse(line);
|
|
121
|
+
} catch {
|
|
122
|
+
conn.destroy();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (msg.type !== "request" || msg.token !== configToken) {
|
|
126
|
+
conn.destroy();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const req = msg.request ?? {};
|
|
130
|
+
const command = String(req.command ?? req.commandPreview ?? "unknown");
|
|
131
|
+
const agentId = req.agentId || void 0;
|
|
132
|
+
evaluate({
|
|
133
|
+
toolName: "Exec",
|
|
134
|
+
args: { command, cwd: req.cwd },
|
|
135
|
+
agentId,
|
|
136
|
+
apiKey,
|
|
137
|
+
policyId,
|
|
138
|
+
baseUrl
|
|
139
|
+
}).then((result) => {
|
|
140
|
+
let decision = "allow-once";
|
|
141
|
+
if (result && (result.decision === "block" || result.decision === "require_approval")) {
|
|
142
|
+
decision = "deny";
|
|
143
|
+
const rule = result.policyContext?.matchedRule;
|
|
144
|
+
console.warn(rule ? `[fastgrc] exec blocked: [${rule}] ${result.reasoning}` : `[fastgrc] exec blocked: ${result.reasoning}`);
|
|
145
|
+
}
|
|
146
|
+
conn.write(JSON.stringify({ type: "decision", decision }) + "\n");
|
|
147
|
+
conn.destroy();
|
|
148
|
+
}).catch(() => {
|
|
149
|
+
conn.write(JSON.stringify({ type: "decision", decision: "allow-once" }) + "\n");
|
|
150
|
+
conn.destroy();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
conn.on("error", () => {
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
server.listen(sockPath, () => {
|
|
157
|
+
try {
|
|
158
|
+
fs2.chmodSync(sockPath, 384);
|
|
159
|
+
} catch {
|
|
160
|
+
}
|
|
161
|
+
console.log(`[fastgrc] exec-approvals server listening on ${sockPath}`);
|
|
162
|
+
});
|
|
163
|
+
server.on("error", (err) => {
|
|
164
|
+
console.warn(`[fastgrc] exec-approvals server error: ${err.message}`);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
81
167
|
var pluginEntry = {
|
|
82
168
|
id: "fastgrc",
|
|
83
169
|
name: "FastGRC Policy Router",
|
|
@@ -92,31 +178,7 @@ var pluginEntry = {
|
|
|
92
178
|
return;
|
|
93
179
|
}
|
|
94
180
|
console.log("[fastgrc] Plugin registered \u2014 before_tool_call hook active");
|
|
95
|
-
const probeEvents = [
|
|
96
|
-
"exec",
|
|
97
|
-
"before_exec",
|
|
98
|
-
"shell",
|
|
99
|
-
"before_shell",
|
|
100
|
-
"command",
|
|
101
|
-
"before_command",
|
|
102
|
-
"run",
|
|
103
|
-
"before_run",
|
|
104
|
-
"tool_call",
|
|
105
|
-
"before_tool",
|
|
106
|
-
"action",
|
|
107
|
-
"before_action",
|
|
108
|
-
"request",
|
|
109
|
-
"before_request",
|
|
110
|
-
"call",
|
|
111
|
-
"before_call"
|
|
112
|
-
];
|
|
113
|
-
for (const evt of probeEvents) {
|
|
114
|
-
api.on(evt, (...args) => {
|
|
115
|
-
console.log(`[fastgrc:hit] ${evt}`, JSON.stringify(args[0])?.slice(0, 120));
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
181
|
api.on("before_tool_call", async (event, ctx) => {
|
|
119
|
-
console.log(`[fastgrc] before_tool_call fired: ${event.toolName}`);
|
|
120
182
|
const result = await evaluate({
|
|
121
183
|
toolName: event.toolName,
|
|
122
184
|
args: event.params,
|
|
@@ -146,9 +208,12 @@ var pluginEntry = {
|
|
|
146
208
|
}
|
|
147
209
|
return void 0;
|
|
148
210
|
});
|
|
211
|
+
startExecApprovalsServer(apiKey, policyId, DEFAULT_BASE_URL2);
|
|
149
212
|
}
|
|
150
213
|
};
|
|
151
214
|
var plugin_default = pluginEntry;
|
|
152
215
|
export {
|
|
153
|
-
plugin_default as default
|
|
216
|
+
plugin_default as default,
|
|
217
|
+
readExecApprovalsConfig,
|
|
218
|
+
startExecApprovalsServer
|
|
154
219
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fastgrc-openclaw",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.30",
|
|
4
4
|
"description": "FastGRC agent compliance plugin for OpenClaw — evaluates every tool call against your policy before it executes",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|