agent-guardrails 0.3.0 → 0.3.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.
package/README.md CHANGED
@@ -1,13 +1,165 @@
1
1
  # Agent Guardrails
2
2
 
3
- **3 seconds to know: Can you safely merge this AI change?**
3
+ **3 秒判断:这次 AI 改动可以安全 merge 吗?**
4
4
 
5
- `agent-guardrails` is the merge gate for AI-written code. It tells you:
6
- - ✅ **Safe to merge** — scope is bounded, tests pass, no drift
7
- - ⚠️ **Needs review** some risk signals, check these files
8
- - ❌ **Don't merge** — out of scope, missing tests, or breaking changes
5
+ [中文简介](#中文简介) | [Quick Start](#快速开始--先看这里) | [Docs](#文档--documentation)
6
+
7
+ `agent-guardrails` **AI 代码合并门** - merge 前检查 AI 改动是否符合预期。
8
+
9
+ - 🎯 **范围验证** - AI 只改了允许的文件
10
+ - ✅ **测试验证** - 测试必须运行
11
+ - 🔍 **漂移检测** - 检测并行抽象、接口变更
12
+ - 🛡 **保护路径** - 关键文件不被触碰
13
+
14
+ ## How it works
15
+
16
+ ![Workflow](./docs/images/workflow.svg)
17
+
18
+ ---
19
+
20
+ ## Before vs After
21
+
22
+ ![Before vs After](./docs/images/before-after.svg)
23
+
24
+ ---
25
+
26
+ ## Rough-Intent Mode
27
+
28
+ Don't have a precise task? Just say what you want in natural language:
29
+
30
+ ![Rough-Intent Mode](./docs/images/rough-intent.svg)
31
+
32
+ ```bash
33
+ # No detailed flags needed - just describe your task
34
+ agent-guardrails plan "加个登录功能" --lang zh-CN --yes
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 快速开始 / 先看这里
40
+
41
+ **30 秒快速体验**(推荐)
42
+
43
+ ```bash
44
+ # 1. 安装
45
+ npm install -g agent-guardrails
46
+
47
+ # 2. 在项目中设置
48
+ cd your-repo
49
+ agent-guardrails setup --agent claude-code
50
+ ```
51
+
52
+ 你可以用其他 Agent:
53
+ - `claude-code` - Claude Code CLI
54
+ - `cursor` - Cursor Editor
55
+ - `codex` - OpenAI Codex CLI
56
+ - `openhands` - OpenHands CLI
57
+ - `openclaw` - OpenClaw CLI
58
+
59
+ **注意**: `setup` 会在项目根目录生成配置文件,输出使用指南。
60
+
61
+ 请复制输出的配置片段到 粘贴到你的 AI 工具中。
62
+
63
+ **3. 开始使用**
64
+ 让你的 AI 按照指南操作代码
65
+ - 输入 `/init` 开始新任务
66
+ - 输入 `/plan` 创建任务计划
67
+ - 输入 `/check` 在完成后检查
68
+
69
+ - 使用 `/review` 获取合并建议
70
+
71
+ **4. 在 merge 前运行检查**
72
+ ```bash
73
+ agent-guardrails check --review
74
+ ```
75
+
76
+ ---
77
+
78
+ ## 核心价值 / Core Value
79
+
80
+ ### 与 传统 AI 编码 | 使用 agent-guardrails |
81
+ |---------------|---------------------------|
82
+ | "AI 改了 47 个文件,不知道为什么" | "AI 改了 3 个文件,都在范围内" |
83
+ | "应该测试过了?" | "测试运行完成,12 通过,0 失败" |
84
+ | "这看起来像是个新模式" | "⚠️ 检测到并行抽象" |
85
+ | "希望不会出问题" | "✓ 可以安全 merge,剩余风险:低" |
86
+ | 5 files, clear scope, clear validation | 12 passed, 0 failed | 0 files, clear scope, clear validation | safe to merge, remaining risk: low |
87
+
88
+ ---
89
+
90
+ ## 适用场景 / When to Use
91
+
92
+ | 场景 | 推荐度 |
93
+ |------|--------|
94
+ | 在真实仓库中使用 AI Agent 的开发者 | ⭐⭐⭐⭐⭐ |
95
+ | 被越界改动、漏测试坑过的团队 | ⭐⭐⭐⭐⭐ |
96
+ | 希望在 merge 前看到清晰验证结果的人 | ⭐⭐⭐⭐ |
97
+
98
+ **不适用场景**:
99
+ - 只想做一次性 prototype 的用户
100
+ - 不关心代码质量和维护性的团队
101
+ - 想找通用静态分析工具的用户
102
+
103
+ ---
104
+
105
+ ## 与竞品对比 / vs. Competitors
106
+
107
+ | 功能 | CodeRabbit | Sonar | agent-guardrails |
108
+ |------|-----------|-------|------------------|
109
+ | 事前约束 | ❌ 事后评论 | ❌ 事后检查 | ✅ |
110
+ | 范围控制 | ❌ | ❌ | ✅ |
111
+ | 任务上下文 | ❌ | ❌ | ✅ |
112
+ | 测试相关性检查 | ❌ | ❌ | ✅ |
113
+
114
+ **我们的优势**: 在代码生成**之前**定义边界,而不是生成**之后**发现问题
115
+ - 主动而非被动
116
+ - 与 AI Agent 巷度集成
117
+ - 支持多种编程语言
118
+
119
+ - 完全开源免费
120
+
121
+ ---
122
+
123
+ ## 安装 / Installation
124
+
125
+ ```bash
126
+ npm install -g agent-guardrails
127
+ ```
128
+
129
+ 在项目目录运行:
130
+ ```bash
131
+ npx agent-guardrails setup --agent <your-agent>
132
+ ```
133
+
134
+ 支持的 Agent:
135
+ - `claude-code` (推荐)
136
+ - `cursor`
137
+ - `codex`
138
+ - `openhands`
139
+ - `openclaw`
140
+
141
+ ---
142
+
143
+ ## 文档 / Documentation
144
+
145
+ - [README.md](./README.md) - 你文档
146
+ - [FAILURE Cases](./docs/FAILURE_Cases.md) - 真实失败案例
147
+ - [Rough-Intent Mode](./docs/Rrough_intent.md) - 模糊请求处理
148
+ - [OSS/Pro 边界](./docs/oss_pro_boundary.md) - 功能对比
149
+
150
+ - [Roadmap](./docs/roadmap.md) - 发展规划
151
+
152
+ - [Proof](./docs/proof.md) - 效果证明
153
+
154
+ - [Pilots](./docs/pilots/README.md) - 试点记录
155
+
156
+ - [Python FastAPI Demo](./examples/python-fastapi-demo/README.md) - Python 示例
157
+ - [TypeScript Demo](./examples/pattern-drift-demo/README.md) - TypeScript 示例
158
+ - [Bounded Scope Demo](./examples/bounded-scope-demo/README.md) - 范围控制示例
159
+ - [Boundary Demo](./examples/boundary-violation-demo/README.md) - 边界检查示例
160
+ - [Interface Drift Demo](./examples/interface-drift-demo/README.md) - 接口变更示例
161
+ - [Source-Test Relevance Demo](./examples/source-test-relevance-demo/README.md) - 测试相关性示例
9
162
 
10
- For real repos, not one-off prototypes.
11
163
 
12
164
  ---
13
165
 
@@ -371,6 +523,58 @@ The first recommended MCP flow is:
371
523
 
372
524
  `suggest_task_contract` and `run_guardrail_check` still exist as lower-level MCP tools, but they are not the preferred first-run chat flow.
373
525
 
526
+ ## Daemon Mode / 守护进程模式
527
+
528
+ Run guardrails automatically in the background while you code:
529
+
530
+ ```bash
531
+ # Start the daemon (background mode)
532
+ agent-guardrails start
533
+
534
+ # Check daemon status
535
+ agent-guardrails status
536
+
537
+ # Stop the daemon
538
+ agent-guardrails stop
539
+
540
+ # Run in foreground (useful for debugging or Docker)
541
+ agent-guardrails start --foreground
542
+ ```
543
+
544
+ ### How It Works
545
+
546
+ The daemon monitors file changes and automatically runs guardrail checks:
547
+ - Watches `src/`, `lib/`, `tests/` by default
548
+ - Debounces checks (5 second interval)
549
+ - Logs to `.agent-guardrails/daemon.log`
550
+
551
+ ### Configuration (`.agent-guardrails/daemon.json`)
552
+
553
+ | Option | Default | Description |
554
+ |--------|---------|-------------|
555
+ | `watchPaths` | `["src/", "lib/", "tests/"]` | Paths to monitor |
556
+ | `ignorePatterns` | `["node_modules", ".git", ...]` | Patterns to ignore |
557
+ | `checkInterval` | `5000` | Debounce interval (ms) |
558
+ | `blockOnHighRisk` | `true` | Block on high-risk findings |
559
+ | `autoFix` | `false` | Auto-fix issues when possible |
560
+
561
+ ### Use Cases
562
+
563
+ - **Local development**: Get instant feedback while coding
564
+ - **CI/CD integration**: Run in containers with `--foreground`
565
+ - **Team guardrails**: Shared daemon config in repo
566
+
567
+ ### Daemon vs Manual Check
568
+
569
+ | Daemon Mode | Manual Check |
570
+ |-------------|--------------|
571
+ | Continuous monitoring | One-time check |
572
+ | Automatic on file change | Run when you want |
573
+ | Background process | Foreground process |
574
+ | Best for active development | Best for pre-commit/CI |
575
+
576
+ ---
577
+
374
578
  ## CLI Fallback Quick Start
375
579
 
376
580
  If you want the shortest manual path, copy this:
@@ -639,3 +843,13 @@ See [CHANGELOG.md](./CHANGELOG.md).
639
843
  ## License
640
844
 
641
845
  MIT
846
+
847
+ ---
848
+
849
+ ## Contributing / 贡献
850
+
851
+ - 🐛 **Bug Reports**: [Open an Issue](https://github.com/logi-cmd/agent-guardrails/issues/new)
852
+ - 💡 **Feature Requests**: [Start a Discussion](https://github.com/logi-cmd/agent-guardrails/discussions)
853
+ - ❓ **Questions**: [Ask in Discussions](https://github.com/logi-cmd/agent-guardrails/discussions)
854
+
855
+ If you find this project helpful, please consider giving it a ⭐️!
@@ -1,5 +1,6 @@
1
1
  import { createFinding } from "../finding.js";
2
2
  import { normalizeChangeType } from "../../utils.js";
3
+ import { execFileSync } from "node:child_process";
3
4
 
4
5
  function toBoolean(value) {
5
6
  if (value === true || value === false) {
@@ -461,5 +462,63 @@ export const ossDetectors = [
461
462
  }));
462
463
  }
463
464
  }
465
+ },
466
+ {
467
+ name: "secrets-safety",
468
+ run({ context, addFinding, t }) {
469
+ const { repoRoot, changedFiles } = context;
470
+ if (!changedFiles || changedFiles.length === 0) return;
471
+
472
+ const patterns = [
473
+ { regex: /(?:api[_-]?key|apikey)\s*[=:]\s*["'][^"']{8,}["']/i, label: "API key" },
474
+ { regex: /(?:password|passwd|pwd)\s*[=:]\s*["'][^"']{6,}["']/i, label: "Password" },
475
+ { regex: /Bearer\s+[A-Za-z0-9\-._~+/]+=*/i, label: "Bearer token" },
476
+ { regex: /-----BEGIN(?:\s+(?:RSA|EC|DSA|OPENSSH|PRIVATE))?[\s-]*PRIVATE KEY-----/, label: "Private key" },
477
+ { regex: /(?:secret|token)\s*[=:]\s*["'][A-Za-z0-9\-._~+/]{16,}["']/i, label: "Secret/token" }
478
+ ];
479
+
480
+ const testLike = /\.(test|spec)\.(js|ts|mjs|cjs|jsx|tsx)$|__tests__|fixtures|mock/i;
481
+ let matched = false;
482
+
483
+ for (const filePath of changedFiles) {
484
+ if (testLike.test(filePath)) continue;
485
+ let content;
486
+ try {
487
+ content = execFileSync(
488
+ "git",
489
+ ["diff", "--cached", "--", filePath],
490
+ { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }
491
+ );
492
+ if (!content.trim()) {
493
+ content = execFileSync(
494
+ "git",
495
+ ["diff", "--", filePath],
496
+ { cwd: repoRoot, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }
497
+ );
498
+ }
499
+ } catch {
500
+ continue;
501
+ }
502
+ const addedLines = content.split("\n").filter((line) => /^\+/.test(line) && !/^\+\+\+/.test(line));
503
+ for (const { regex, label } of patterns) {
504
+ for (const line of addedLines) {
505
+ if (regex.test(line)) {
506
+ matched = true;
507
+ addFinding(createFinding({
508
+ severity: "warning",
509
+ category: "risk",
510
+ code: "secrets-safety",
511
+ message: t("findings.secretsSafetyDetected", { file: filePath, type: label }),
512
+ action: t("actions.moveSecretToEnv"),
513
+ files: [filePath]
514
+ }));
515
+ break;
516
+ }
517
+ }
518
+ if (matched) break;
519
+ }
520
+ if (matched) break;
521
+ }
522
+ }
464
523
  }
465
524
  ];
package/lib/cli.js CHANGED
@@ -4,7 +4,9 @@ import { runMcp } from "./commands/mcp.js";
4
4
  import { runSetup } from "./commands/setup.js";
5
5
  import { createTranslator, supportedLocales } from "./i18n.js";
6
6
  import { runPlan } from "./commands/plan.js";
7
- import { supportedAdapters, supportedPresets } from "./utils.js";
7
+ import { runGenerateAgentsMd } from "./commands/agents-md.js";
8
+ import { startDaemon, stopDaemon, showDaemonStatus } from "./commands/daemon.js";
9
+ import { supportedAdapters, supportedPresets, readOwnPackageJson } from "./utils.js";
8
10
 
9
11
  function parseArgs(argv) {
10
12
  const positional = [];
@@ -42,14 +44,28 @@ ${t("cli.usage")}
42
44
  agent-guardrails setup [targetDir] --agent <name> [--preset <name>] [--lang <locale>] [--json] [--write-repo-config]
43
45
  agent-guardrails plan --task "<task description>" [--intended-files "src/service.js,tests/service.test.js"] [--allowed-change-types "implementation-only"] [--allow-paths "src/,tests/"] [--required-commands "npm test"] [--evidence ".agent-guardrails/evidence/current-task.md"] [--risk-level high] [--lang <locale>] [--print-only]
44
46
  agent-guardrails check [--contract-path <path>] [--base-ref <ref>] [--commands-run "npm test"] [--review] [--lang <locale>] [--json]
47
+ agent-guardrails start [--foreground] - ${t("cli.startSummary")}
48
+ agent-guardrails stop - ${t("cli.stopSummary")}
49
+ agent-guardrails status - ${t("cli.statusSummary")}
50
+ agent-guardrails generate-agents [targetDir] [--preset <name>] [--lang <locale>]
45
51
  agent-guardrails mcp
52
+ agent-guardrails --version
53
+
54
+ ${t("cli.globalOptions")}
55
+ --version, -v ${t("cli.versionSummary") ?? "Show version number"}
56
+ --help, -h ${t("cli.helpSummary") ?? "Show this help"}
57
+ --lang <locale> ${t("cli.langSummary") ?? "Language for output (en, zh-CN)"}
46
58
 
47
59
  ${t("cli.commands")}
48
- init ${t("cli.initSummary")}
49
- setup ${t("cli.setupSummary")}
50
- plan ${t("cli.planSummary")}
51
- check ${t("cli.checkSummary")}
52
- mcp ${t("cli.mcpSummary")}
60
+ init ${t("cli.initSummary")}
61
+ setup ${t("cli.setupSummary")}
62
+ plan ${t("cli.planSummary")}
63
+ check ${t("cli.checkSummary")}
64
+ start ${t("cli.startSummary")}
65
+ stop ${t("cli.stopSummary")}
66
+ status ${t("cli.statusSummary")}
67
+ generate-agents Generate AGENTS.md for Harness Engineering
68
+ mcp ${t("cli.mcpSummary")}
53
69
 
54
70
  ${t("cli.supportedPresets")}
55
71
  ${supportedPresets.join(", ")}
@@ -67,6 +83,12 @@ export async function runCli(argv) {
67
83
  const [command, ...rest] = positional;
68
84
  const locale = flags.lang ?? null;
69
85
 
86
+ if (flags.version || flags.v) {
87
+ const pkg = readOwnPackageJson();
88
+ console.log(`agent-guardrails v${pkg.version}`);
89
+ return;
90
+ }
91
+
70
92
  if (!command || command === "help" || flags.help) {
71
93
  printHelp(locale);
72
94
  return;
@@ -97,6 +119,26 @@ export async function runCli(argv) {
97
119
  return;
98
120
  }
99
121
 
122
+ if (command === "start") {
123
+ await startDaemon(process.cwd(), { locale, foreground: flags.foreground || false });
124
+ return;
125
+ }
126
+
127
+ if (command === "stop") {
128
+ stopDaemon(process.cwd(), { locale });
129
+ return;
130
+ }
131
+
132
+ if (command === "status") {
133
+ showDaemonStatus(process.cwd(), { locale });
134
+ return;
135
+ }
136
+
137
+ if (command === "generate-agents" || command === "gen-agents") {
138
+ await runGenerateAgentsMd({ positional: rest, flags, locale });
139
+ return;
140
+ }
141
+
100
142
  const { t } = createTranslator(locale);
101
143
  throw new Error(t("cli.unknownCommand", { command }));
102
144
  }
@@ -0,0 +1,281 @@
1
+ /**
2
+ * AGENTS.md Generator
3
+ *
4
+ * 基于 Harness Engineering 范式,生成符合 OpenAI 推荐的渐进式文档结构
5
+ *
6
+ * OpenAI 团队的 AGENTS.md 结构:
7
+ * - 精简目录(~100行)
8
+ * - 渐进式披露
9
+ * - 指向 docs/ 目录
10
+ */
11
+
12
+ import fs from "node:fs";
13
+ import path from "node:path";
14
+ import { createTranslator } from "../i18n.js";
15
+ import { ensureDirectory, readConfig } from "../utils.js";
16
+
17
+ // AGENTS.md 模板
18
+ const AGENTS_MD_TEMPLATE = `# AGENTS.md
19
+
20
+ > 此文件由 agent-guardrails 自动生成
21
+ > 基于 Harness Engineering 范式,帮助 AI Agent 更好地理解项目
22
+
23
+ ## 项目概述
24
+
25
+ <!-- 简短描述项目是做什么的 -->
26
+
27
+ ## 快速开始
28
+
29
+ \`\`\`bash
30
+ # 安装依赖
31
+ npm install
32
+
33
+ # 运行测试
34
+ npm test
35
+
36
+ # 启动开发服务器
37
+ npm run dev
38
+ \`\`\`
39
+
40
+ ## 架构约束
41
+
42
+ ### 分层架构
43
+
44
+ \`\`\`
45
+ ┌─────────────────────────────────────────┐
46
+ │ 表现层 (UI) │
47
+ ├─────────────────────────────────────────┤
48
+ │ 应用层 (Services) │
49
+ ├─────────────────────────────────────────┤
50
+ │ 领域层 (Domain) │
51
+ ├─────────────────────────────────────────┤
52
+ │ 基础设施层 (Infra) │
53
+ └─────────────────────────────────────────┘
54
+ \`\`\`
55
+
56
+ ### 依赖规则
57
+
58
+ - 上层可以依赖下层
59
+ - 下层不能依赖上层
60
+ - 同层之间尽量独立
61
+
62
+ ## 代码风格
63
+
64
+ ### 命名约定
65
+
66
+ - 文件名: kebab-case (例: user-service.ts)
67
+ - 类名: PascalCase (例: UserService)
68
+ - 函数名: camelCase (例: getUserById)
69
+ - 常量: UPPER_SNAKE_CASE (例: MAX_RETRY_COUNT)
70
+
71
+ ### 目录结构
72
+
73
+ \`\`\`
74
+ src/
75
+ ├── modules/ # 功能模块
76
+ │ ├── user/
77
+ │ │ ├── user.service.ts
78
+ │ │ ├── user.controller.ts
79
+ │ │ └── user.types.ts
80
+ │ └── ...
81
+ ├── shared/ # 共享代码
82
+ │ ├── utils/
83
+ │ └── types/
84
+ └── config/ # 配置文件
85
+ \`\`\`
86
+
87
+ ## 禁止事项
88
+
89
+ ❌ 不要直接修改数据库迁移文件
90
+ ❌ 不要跳过测试提交代码
91
+ ❌ 不要在 src 外创建新的源代码目录
92
+ ❌ 不要使用 any 类型(除非有充分理由)
93
+
94
+ ## 详细文档
95
+
96
+ 更多信息请查看 docs/ 目录:
97
+
98
+ - [架构设计](./docs/ARCHITECTURE.md)
99
+ - [API 文档](./docs/API.md)
100
+ - [测试指南](./docs/TESTING.md)
101
+
102
+ ---
103
+ *此文件由 agent-guardrails 生成 | Harness Engineering Ready*
104
+ `;
105
+
106
+ // docs/ARCHITECTURE.md 模板
107
+ const ARCHITECTURE_MD_TEMPLATE = `# 架构设计
108
+
109
+ ## 系统架构
110
+
111
+ <!-- 描述系统的整体架构 -->
112
+
113
+ ## 模块划分
114
+
115
+ <!-- 描述主要模块及其职责 -->
116
+
117
+ ## 数据流
118
+
119
+ <!-- 描述数据如何在系统中流动 -->
120
+
121
+ ## 关键决策
122
+
123
+ <!-- 记录重要的架构决策及其原因 -->
124
+
125
+ ## 待办事项
126
+
127
+ <!-- 需要改进的地方 -->
128
+ `;
129
+
130
+ // docs/TESTING.md 模板
131
+ const TESTING_MD_TEMPLATE = `# 测试指南
132
+
133
+ ## 测试策略
134
+
135
+ ### 单元测试
136
+
137
+ - 每个模块都应该有对应的单元测试
138
+ - 测试文件放在 \\\`__tests__\\\` 目录或与源文件同级
139
+ - 使用 jest 作为测试框架
140
+
141
+ \`\`\`bash
142
+ # 运行单元测试
143
+ npm test
144
+
145
+ # 运行特定测试
146
+ npm test -- user.service.test.ts
147
+ \`\`\`
148
+
149
+ ### 集成测试
150
+
151
+ - 测试模块之间的交互
152
+ - 使用测试数据库
153
+
154
+ ### E2E 测试
155
+
156
+ - 测试完整的用户流程
157
+ - 使用 Cypress 或 Playwright
158
+
159
+ ## 测试覆盖率
160
+
161
+ 目标:80% 以上的代码覆盖率
162
+
163
+ \`\`\`bash
164
+ # 查看覆盖率报告
165
+ npm run test:coverage
166
+ \`\`\`
167
+
168
+ ## Mock 规则
169
+
170
+ - 外部服务必须 mock
171
+ - 数据库操作使用测试数据库
172
+ - 时间相关的测试使用固定时间
173
+ `;
174
+
175
+ /**
176
+ * 生成 AGENTS.md 文件
177
+ */
178
+ export function generateAgentsMd(options) {
179
+ const { repoRoot, preset, locale } = options;
180
+ const t = createTranslator(locale);
181
+
182
+ const agentsMdPath = path.join(repoRoot, "AGENTS.md");
183
+ const docsDir = path.join(repoRoot, "docs");
184
+
185
+ // 检查是否已存在
186
+ if (fs.existsSync(agentsMdPath)) {
187
+ return {
188
+ ok: false,
189
+ reason: "AGENTS.md already exists",
190
+ path: agentsMdPath
191
+ };
192
+ }
193
+
194
+ // 创建 docs 目录
195
+ ensureDirectory(docsDir);
196
+
197
+ // 生成 AGENTS.md
198
+ fs.writeFileSync(agentsMdPath, AGENTS_MD_TEMPLATE, "utf8");
199
+
200
+ // 生成 docs/ARCHITECTURE.md
201
+ const architecturePath = path.join(docsDir, "ARCHITECTURE.md");
202
+ if (!fs.existsSync(architecturePath)) {
203
+ fs.writeFileSync(architecturePath, ARCHITECTURE_MD_TEMPLATE, "utf8");
204
+ }
205
+
206
+ // 生成 docs/TESTING.md
207
+ const testingPath = path.join(docsDir, "TESTING.md");
208
+ if (!fs.existsSync(testingPath)) {
209
+ fs.writeFileSync(testingPath, TESTING_MD_TEMPLATE, "utf8");
210
+ }
211
+
212
+ return {
213
+ ok: true,
214
+ files: [
215
+ agentsMdPath,
216
+ architecturePath,
217
+ testingPath
218
+ ],
219
+ message: "AGENTS.md generated successfully"
220
+ };
221
+ }
222
+
223
+ /**
224
+ * 更新 AGENTS.md
225
+ */
226
+ export function updateAgentsMd(options) {
227
+ const { repoRoot, section, content, locale } = options;
228
+
229
+ const agentsMdPath = path.join(repoRoot, "AGENTS.md");
230
+
231
+ if (!fs.existsSync(agentsMdPath)) {
232
+ return {
233
+ ok: false,
234
+ reason: "AGENTS.md not found. Run 'agent-guardrails generate-agents' first."
235
+ };
236
+ }
237
+
238
+ const currentContent = fs.readFileSync(agentsMdPath, "utf8");
239
+
240
+ // 根据 section 更新对应部分
241
+ // 这里可以扩展更多 section 的更新逻辑
242
+
243
+ return {
244
+ ok: true,
245
+ message: "AGENTS.md updated"
246
+ };
247
+ }
248
+
249
+ /**
250
+ * CLI 命令入口
251
+ */
252
+ export async function runGenerateAgentsMd({ positional, flags, locale = null }) {
253
+ const repoRoot = positional[0] ? path.resolve(positional[0]) : process.cwd();
254
+ const preset = flags.preset || "node-service";
255
+
256
+ console.log("🔧 Generating AGENTS.md...\n");
257
+
258
+ const result = generateAgentsMd({
259
+ repoRoot,
260
+ preset,
261
+ locale: flags.lang || locale
262
+ });
263
+
264
+ if (result.ok) {
265
+ console.log("✅ AGENTS.md generated successfully!\n");
266
+ console.log("Files created:");
267
+ result.files.forEach(file => {
268
+ console.log(` - ${path.relative(repoRoot, file)}`);
269
+ });
270
+ console.log("\n📖 What's next:");
271
+ console.log(" 1. Review and customize AGENTS.md for your project");
272
+ console.log(" 2. Update docs/ARCHITECTURE.md with your architecture");
273
+ console.log(" 3. Update docs/TESTING.md with your testing strategy");
274
+ console.log(" 4. Point your AI agent to AGENTS.md");
275
+ } else {
276
+ console.log(`⚠️ ${result.reason}`);
277
+ console.log(` Path: ${result.path}`);
278
+ }
279
+
280
+ return result;
281
+ }
@@ -475,6 +475,11 @@ function printTextResult(result, t, { reviewMode = false } = {}) {
475
475
  if (result.failures.length === 0) {
476
476
  console.log(`\n${t("check.allPassed")}`);
477
477
  }
478
+
479
+ if (result.runtime?.costHints?.entries?.length > 0) {
480
+ console.log(`\n${t("check.costAwareness")}`);
481
+ console.log(result.runtime.costHints.entries.map((entry) => `- ${t(entry.key, entry.vars)}`).join("\n"));
482
+ }
478
483
  }
479
484
 
480
485
  function printJsonResult(result) {