agent-guardrails 0.3.3 → 0.3.5

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
@@ -138,6 +138,20 @@ npx agent-guardrails setup --agent <your-agent>
138
138
  - `openhands`
139
139
  - `openclaw`
140
140
 
141
+ ### 更新 / Update
142
+
143
+ 如果通过 **npm 全局安装**:
144
+ ```bash
145
+ npm update -g agent-guardrails
146
+ ```
147
+
148
+ 如果通过 **npx / MCP 使用**(不需要改配置文件):
149
+ ```bash
150
+ # 清除 npx 缓存,下次启动时自动拉取最新版
151
+ npm cache clean --force
152
+ # 然后重启你的 AI 工具(Claude Code / Cursor 等)即可
153
+ ```
154
+
141
155
  ---
142
156
 
143
157
  ## 文档 / Documentation
@@ -573,6 +587,23 @@ The daemon monitors file changes and automatically runs guardrail checks:
573
587
  | Background process | Foreground process |
574
588
  | Best for active development | Best for pre-commit/CI |
575
589
 
590
+ ### MCP Integration / MCP 集成
591
+
592
+ AI agents can read daemon results via the `read_daemon_status` MCP tool — no polling needed:
593
+
594
+ ```json
595
+ {
596
+ "mcpServers": {
597
+ "agent-guardrails": {
598
+ "command": "npx",
599
+ "args": ["agent-guardrails", "mcp"]
600
+ }
601
+ }
602
+ }
603
+ ```
604
+
605
+ The agent calls `read_daemon_status` after code changes to check the latest guardrail result, including findings, risks, and cost hints.
606
+
576
607
  ---
577
608
 
578
609
  ## CLI Fallback Quick Start
@@ -23,6 +23,38 @@ const DAEMON_LOG_FILE = ".agent-guardrails/daemon.log";
23
23
  const DAEMON_CONFIG_FILE = ".agent-guardrails/daemon.json";
24
24
  const DAEMON_INFO_FILE = ".agent-guardrails/daemon-info.json";
25
25
 
26
+ /**
27
+ * 注入/移除 AGENTS.md 中的守护进程规则
28
+ */
29
+
30
+ const DAEMON_AGENTS_MARKER_START = "<!-- agent-guardrails:daemon:start -->";
31
+ const DAEMON_AGENTS_MARKER_END = "<!-- agent-guardrails:daemon:end -->";
32
+ const DAEMON_AGENTS_BLOCK = `\n${DAEMON_AGENTS_MARKER_START}
33
+ ## Daemon Mode / 守护模式
34
+
35
+ Daemon 正在运行。每次修改文件后,请调用 \`read_daemon_status\` MCP 工具检查 guardrail 结果。如果有 error 级别的 finding,在继续之前先修复。
36
+ ${DAEMON_AGENTS_MARKER_END}\n`;
37
+
38
+ function injectDaemonRule(repoRoot) {
39
+ const agentsFile = path.join(repoRoot, "AGENTS.md");
40
+ if (!fs.existsSync(agentsFile)) return;
41
+ let content = fs.readFileSync(agentsFile, "utf8");
42
+ if (content.includes(DAEMON_AGENTS_MARKER_START)) return; // 已存在
43
+ content = content.trimEnd() + DAEMON_AGENTS_BLOCK;
44
+ fs.writeFileSync(agentsFile, content, "utf8");
45
+ }
46
+
47
+ function removeDaemonRule(repoRoot) {
48
+ const agentsFile = path.join(repoRoot, "AGENTS.md");
49
+ if (!fs.existsSync(agentsFile)) return;
50
+ let content = fs.readFileSync(agentsFile, "utf8");
51
+ const startIdx = content.indexOf(DAEMON_AGENTS_MARKER_START);
52
+ const endIdx = content.indexOf(DAEMON_AGENTS_MARKER_END);
53
+ if (startIdx === -1 || endIdx === -1) return;
54
+ content = content.slice(0, startIdx).trimEnd() + "\n" + content.slice(endIdx + DAEMON_AGENTS_MARKER_END.length).trimStart() + "\n";
55
+ fs.writeFileSync(agentsFile, content, "utf8");
56
+ }
57
+
26
58
  /**
27
59
  * 默认守护配置
28
60
  */
@@ -219,6 +251,7 @@ export async function startDaemon(repoRoot, options = {}) {
219
251
  const pid = await waitForPidFile(pidFile, 5000);
220
252
 
221
253
  if (pid) {
254
+ injectDaemonRule(repoRoot);
222
255
  console.log(`${t("daemon.started")}`);
223
256
  console.log(` PID: ${pid}`);
224
257
  console.log(`\n${t("daemon.logFile")}: ${DAEMON_LOG_FILE}`);
@@ -276,6 +309,8 @@ export async function stopDaemon(repoRoot, options = {}) {
276
309
  fs.unlinkSync(pidFile);
277
310
  }
278
311
 
312
+ removeDaemonRule(repoRoot);
313
+
279
314
  console.log(`\n${t("daemon.stopped")}`);
280
315
  return { success: true };
281
316
  } catch (error) {
@@ -197,6 +197,18 @@ export async function createCheckRunner(repoRoot, config, log, t) {
197
197
  .then((result) => {
198
198
  const ok = result?.ok;
199
199
  log(ok ? "Check passed" : "Check completed with issues");
200
+
201
+ // 保存结构化结果供 MCP 读取
202
+ try {
203
+ const resultFile = path.join(repoRoot, ".agent-guardrails", "daemon-result.json");
204
+ const dir = path.dirname(resultFile);
205
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
206
+ fs.writeFileSync(resultFile, JSON.stringify({
207
+ timestamp: new Date().toISOString(),
208
+ ok: !!ok,
209
+ result
210
+ }, null, 2));
211
+ } catch { /* ignore */ }
200
212
  })
201
213
  .catch((err) => {
202
214
  log(`Check error: ${err.message}`);
package/lib/mcp/server.js CHANGED
@@ -1,3 +1,5 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
1
3
  import { executeCheck } from "../commands/check.js";
2
4
  import {
3
5
  finishAgentNativeLoop,
@@ -193,6 +195,20 @@ const TOOL_DEFINITIONS = [
193
195
  required: ["task"],
194
196
  additionalProperties: false
195
197
  }
198
+ },
199
+ {
200
+ name: "read_daemon_status",
201
+ description: "Read the latest daemon check result and status. Returns daemon running state, check count, and the structured result of the most recent guardrail check. Call this after code changes to check if the daemon detected any issues.",
202
+ inputSchema: {
203
+ type: "object",
204
+ properties: {
205
+ repoRoot: {
206
+ type: "string",
207
+ description: "Absolute path to the repository root."
208
+ }
209
+ },
210
+ additionalProperties: false
211
+ }
196
212
  }
197
213
  ];
198
214
 
@@ -428,6 +444,35 @@ async function callTool(name, args, defaultRepoRoot) {
428
444
  });
429
445
  }
430
446
 
447
+ if (name === "read_daemon_status") {
448
+ const repoRoot = args.repoRoot || defaultRepoRoot;
449
+ const { isDaemonRunning, getDaemonConfig } = await import("../commands/daemon.js");
450
+ const status = isDaemonRunning(repoRoot);
451
+ const config = getDaemonConfig(repoRoot);
452
+
453
+ const resultPath = path.join(repoRoot, ".agent-guardrails", "daemon-result.json");
454
+ let lastResult = null;
455
+ try {
456
+ if (fs.existsSync(resultPath)) {
457
+ lastResult = JSON.parse(fs.readFileSync(resultPath, "utf8"));
458
+ }
459
+ } catch { /* ignore */ }
460
+
461
+ return createJsonResult({
462
+ running: status.running,
463
+ pid: status.pid || null,
464
+ startTime: status.startTime || null,
465
+ checksRun: status.checksRun || 0,
466
+ lastCheck: status.lastCheck || null,
467
+ config: {
468
+ watchPaths: config.watchPaths,
469
+ checkInterval: config.checkInterval,
470
+ blockOnHighRisk: config.blockOnHighRisk
471
+ },
472
+ lastResult
473
+ });
474
+ }
475
+
431
476
  throw createError(-32601, `Unknown tool "${name}".`);
432
477
  }
433
478
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-guardrails",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "mcpName": "io.github.logi-cmd/agent-guardrails",
5
5
  "description": "Production guardrails for AI coding agents",
6
6
  "type": "module",