repo-audit-tool 1.2.1 → 1.3.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/BEST-PRACTICES.md CHANGED
@@ -159,7 +159,7 @@ gh repo edit <org>/dsh-<name> --add-topic deepseek-harness --add-topic dsh-plugi
159
159
  2. **peer 同范围复制进 devDependencies**(社区事实标准):peer 不进自身依赖树 → tsc/测试/CI 找不到类型
160
160
  3. **单库化坑(subagent-router 实战)**:单库独立安装不装宿主包的 peer——**运行时可达的宿主 peer 包全部显式进 devDependencies**;判定法:`npm test` 报 `Cannot find package` 逐个补
161
161
  4. **devDep 精确 pin 特例**:`dsh-client-ui-slots` 的 module augmentation 要求与 runtime 解析副本一致,caret 会漂移致 SlotMap 双副本 → 该包 pin 精确版本(0.2.0 踩过 TS2664/TS2345)
162
- 5. **版本锁定分工**:范围写 package.json(caret),具体版靠提交入库的 `package-lock.json`;CI `npm ci --legacy-peer-deps`(dsh alpha 生态 peer 链不完整)
162
+ 5. **版本锁定分工**:范围写 package.json(caret),具体版靠提交入库的 `package-lock.json`;CI `npm ci --legacy-peer-deps`(dsh alpha 生态 peer 链不完整)。锁文件的核心价值在**被消费**:CI/验证链必须实际安装它(`npm ci` / `pip install -r requirements.lock`)——只入库不安装是装饰性合规;`requirements.lock` 非 pip 原生锁格式,没有默认消费者,CI 须显式安装;零依赖仓(依赖声明为空)无锁对象,可豁免。
163
163
 
164
164
  ### 5.3 dual ESM/CJS(外部调研结论)
165
165
 
package/PUBLISHING.md CHANGED
@@ -4,12 +4,17 @@
4
4
 
5
5
  | 项 | 状态 |
6
6
  |---|---|
7
- | npm | `repo-audit-tool` v1.2.0(已发布,latest) |
7
+ | npm | `repo-audit-tool` v1.2.3(latest,CI 自动发布) |
8
8
  | GitHub | `NinjaSln-labs/repo-audit` master;发版 tag `v*` |
9
9
  | 本地验证 | 自审计 100/A,验证链 4/4,测试 3/3,CI 全绿 |
10
10
 
11
11
  ## 版本历史
12
12
 
13
+ - **1.2.3** — package.json 补充 `repository` 字段,修复 npm provenance E422;
14
+ 首次 Trusted Publisher(OIDC)tag 触发自动发布(2026-09-06)
15
+ - **1.2.2** — publish CI 修复:node 20→22 + npm 条件升级,修复 EBADENGINE;
16
+ tag 发布因 npm 已存在 1.2.1 未出包(OIDC 鉴权链路已验证通过)(2026-09-06)
17
+ - **1.2.1** — README 链接改为绝对 URL(修复 npm 页面 404);手动发布(2026-09-06)
13
18
  - **1.2.0** — 开源就绪:补充 AGENTS.md、CI/publish workflow 适配、json_field monorepo 感知、
14
19
  fallback_field 数组格式修复、英文 README、参数类型校验、占位符残留扫描(2026-09-06)
15
20
  - 首次发布:`npm publish --access public`(手动 bootstrap)
@@ -44,11 +49,11 @@ git push && git push --tags
44
49
  ## 首次发布(已完成)
45
50
 
46
51
  1. **npm 包创建**:`npm publish --access public`(v1.2.0,2026-09-06)
47
- 2. **Trusted Publisher 配置**(下一步):npmjs.com → 包设置 → Trusted Publisher →
52
+ 2. **Trusted Publisher 配置**:npmjs.com → 包设置 → Trusted Publisher →
48
53
  - Repository: `NinjaSln-labs/repo-audit`
49
54
  - Workflow: `publish.yml`
50
- - Branch: `master`
51
- 3. **验证**:`npm view repo-audit-tool dist-tags` → `{ latest: '1.2.0' }` ✓
55
+ - Branch: `master`(注:tag 触发场景 npm 亦放行,v1.2.2 实测通过)
56
+ 3. **验证**:`npm view repo-audit-tool dist-tags` → latest 已更新 ✓
52
57
 
53
58
  ## 发布后验证
54
59
 
@@ -0,0 +1,240 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "repo-audit 文档索引",
4
+ "description": "AI Agent 可读的文档索引 — 包含所有文档的元数据、结构、和调用协议",
5
+ "version": "1.3.0",
6
+ "updated": "2026-09-06",
7
+ "repo": "NinjaSln-labs/repo-audit",
8
+ "npm": "repo-audit-tool",
9
+ "pages": "https://ninjasln-labs.github.io/repo-audit/",
10
+
11
+ "entry_points": {
12
+ "json_index": "/AGENT-INDEX.json",
13
+ "schema": "/SCHEMA.json",
14
+ "protocol": "/AGENT-PROTOCOL.md",
15
+ "human_guide": "/repo-audit/HUMAN-GUIDE.md",
16
+ "agent_guide": "/repo-audit/AGENT-GUIDE.md"
17
+ },
18
+
19
+ "tool": {
20
+ "name": "repo-audit",
21
+ "description": "仓库标准化审计工具 + 工程脚手架生成器(零依赖)",
22
+ "bin": "repo-audit",
23
+ "version": "1.3.0",
24
+ "language": "JavaScript (ESM)",
25
+ "runtime": "Node.js >= 18",
26
+ "dependencies": [],
27
+ "license": "MIT",
28
+
29
+ "invocation": {
30
+ "command": "repo-audit [options]",
31
+ "options": {
32
+ "--repo": { "type": "string", "default": ".", "description": "目标仓库路径" },
33
+ "--type": { "type": "string", "description": "强制指定分类(跳过自动检测)" },
34
+ "--format": { "type": "string", "enum": ["md", "json", "both"], "default": "both", "description": "输出格式" },
35
+ "--output": { "type": "string", "default": "<repo>/audit-report/", "description": "输出目录" },
36
+ "--llm-provider": { "type": "string", "description": "LLM 协议:openai/anthropic 或厂商别名" },
37
+ "--llm-model": { "type": "string", "description": "模型名称" },
38
+ "--strict": { "type": "boolean", "default": false, "description": "严格模式:Critical/Major 即 exit 1" },
39
+ "--rules": { "type": "string", "description": "自定义规则 YAML(可多次)" },
40
+ "--dim": { "type": "string", "description": "只审计指定维度(可多次)" },
41
+ "--feedback": { "type": "string", "description": "提交反馈(创建 GitHub Issue)" },
42
+ "--help": { "type": "boolean", "description": "显示帮助" }
43
+ },
44
+
45
+ "exit_codes": {
46
+ "0": "审计通过(无 Critical/Major 或 --strict 未启用)",
47
+ "1": "有 Critical/Major 发现且 --strict 启用",
48
+ "2": "参数错误",
49
+ "3": "目标不是 git 仓库"
50
+ }
51
+ },
52
+
53
+ "environment_variables": {
54
+ "LLM_PROVIDER": "LLM 协议(openai/anthropic/none),也可用厂商别名如 deepseek/qwen/glm",
55
+ "LLM_API_KEY": "API Key(必须手动指定)",
56
+ "LLM_MODEL": "模型名称",
57
+ "LLM_BASE_URL": "自定义 API 端点(OpenAI 兼容厂商必填)",
58
+ "REPO_AUDIT_TYPES": "自定义分类列表(JSON 数组)"
59
+ }
60
+ },
61
+
62
+ "audit": {
63
+ "dimensions": [
64
+ {
65
+ "id": "docs",
66
+ "label": "文档",
67
+ "rules": ["DOC-001", "DOC-002", "DOC-003", "DOC-003b", "DOC-004", "DOC-005", "DOC-006", "DOC-007"],
68
+ "description": "README/LICENSE/CONTRIBUTING/SECURITY 等文档完整性"
69
+ },
70
+ {
71
+ "id": "git",
72
+ "label": "Git",
73
+ "rules": ["GIT-001", "GIT-002", "GIT-003", "GIT-004"],
74
+ "description": "commit 规范、分支策略、scaffold 管理"
75
+ },
76
+ {
77
+ "id": "quality",
78
+ "label": "质量",
79
+ "rules": ["QUA-001", "QUA-002", "QUA-003", "QUA-004", "QUA-005"],
80
+ "description": "构建配置、测试、lint、typecheck"
81
+ },
82
+ {
83
+ "id": "security",
84
+ "label": "安全",
85
+ "rules": ["SEC-001", "SEC-002", "SEC-003", "SEC-004"],
86
+ "description": "密钥泄露、依赖漏洞、权限配置"
87
+ }
88
+ ],
89
+
90
+ "scoring": {
91
+ "formula": "score = 100 - (critical × 25) - (major × 10) - (minor × 3)",
92
+ "grades": {
93
+ "A": ">= 90",
94
+ "B": ">= 80",
95
+ "C": ">= 70",
96
+ "D": ">= 60",
97
+ "F": "< 60"
98
+ },
99
+ "note": "score 和 grade 不在 JSON 输出中,Agent 需根据 summary 字段自行计算"
100
+ },
101
+
102
+ "categories": [
103
+ "dsh-plugin", "python-app", "go-service", "content", "sandbox",
104
+ "archive", "product-oss", "javascript", "typescript", "java",
105
+ "python", "rust", "cpp", "dotnet", "php", "ruby", "unknown"
106
+ ]
107
+ },
108
+
109
+ "documents": [
110
+ {
111
+ "id": "human-guide",
112
+ "title": "人类使用手册",
113
+ "path": "/repo-audit/HUMAN-GUIDE.md",
114
+ "url": "https://ninjasln-labs.github.io/repo-audit/repo-audit/HUMAN-GUIDE.md",
115
+ "audience": "human",
116
+ "sections": [
117
+ "一、安装",
118
+ "二、快速开始",
119
+ "三、命令行参数",
120
+ "四、环境变量",
121
+ "五、输出说明",
122
+ "六、退出码",
123
+ "七、审计维度说明",
124
+ "八、扩展指南",
125
+ "九、故障排查",
126
+ "十、与 scaffold 的配合",
127
+ "十一、操作授权与完成路径",
128
+ "十二、新特性说明"
129
+ ]
130
+ },
131
+ {
132
+ "id": "agent-guide",
133
+ "title": "Agent 操作手册",
134
+ "path": "/repo-audit/AGENT-GUIDE.md",
135
+ "url": "https://ninjasln-labs.github.io/repo-audit/repo-audit/AGENT-GUIDE.md",
136
+ "audience": "agent",
137
+ "sections": [
138
+ "一、工具定位",
139
+ "二、调用协议",
140
+ "三、输出解析",
141
+ "四、标准操作流程",
142
+ "五、错误处理协议",
143
+ "六、性能参考",
144
+ "七、Agent 决策树",
145
+ "八、操作授权与完成路径",
146
+ "九、快速参考卡",
147
+ "十、反馈通道"
148
+ ]
149
+ },
150
+ {
151
+ "id": "audit-methodology",
152
+ "title": "审计方法论",
153
+ "path": "/AUDIT.md",
154
+ "url": "https://github.com/NinjaSln-labs/repo-audit/blob/master/AUDIT.md",
155
+ "audience": "both",
156
+ "description": "评分体系、规则设计、维度划分"
157
+ },
158
+ {
159
+ "id": "best-practices",
160
+ "title": "最佳实践标准",
161
+ "path": "/BEST-PRACTICES.md",
162
+ "url": "https://github.com/NinjaSln-labs/repo-audit/blob/master/BEST-PRACTICES.md",
163
+ "audience": "both",
164
+ "description": "工程仓库应满足的标准化检查项"
165
+ },
166
+ {
167
+ "id": "classification",
168
+ "title": "分类检测说明",
169
+ "path": "/REPO-CLASSIFICATION.md",
170
+ "url": "https://github.com/NinjaSln-labs/repo-audit/blob/master/REPO-CLASSIFICATION.md",
171
+ "audience": "both",
172
+ "description": "18 种仓库类型识别逻辑,置信度评分"
173
+ },
174
+ {
175
+ "id": "templates",
176
+ "title": "脚手架模板",
177
+ "path": "/templates/README.md",
178
+ "url": "https://github.com/NinjaSln-labs/repo-audit/blob/master/templates/README.md",
179
+ "audience": "both",
180
+ "description": "从零生成符合规范的工程脚手架"
181
+ },
182
+ {
183
+ "id": "schema",
184
+ "title": "审计报告 JSON Schema",
185
+ "path": "/SCHEMA.json",
186
+ "url": "https://ninjasln-labs.github.io/repo-audit/SCHEMA.json",
187
+ "audience": "agent",
188
+ "format": "json-schema",
189
+ "description": "JSON Schema 定义,用于验证审计报告输出"
190
+ }
191
+ ],
192
+
193
+ "feedback": {
194
+ "description": "反馈通道 — Agent 可通过 GitHub Issues API 检测和处理用户反馈",
195
+ "label": "audit-feedback",
196
+ "repo": "NinjaSln-labs/repo-audit",
197
+
198
+ "detect": {
199
+ "command": "gh issue list --repo NinjaSln-labs/repo-audit --label audit-feedback --state open --json number,title,createdAt,body",
200
+ "description": "列出未处理的反馈"
201
+ },
202
+ "view": {
203
+ "command": "gh issue view <NUMBER> --repo NinjaSln-labs/repo-audit --json title,body,labels,createdAt",
204
+ "description": "获取单条反馈详情"
205
+ },
206
+ "close": {
207
+ "command": "gh issue close <NUMBER> --repo NinjaSln-labs/repo-audit --comment '已处理:[处理说明]'",
208
+ "description": "反馈已处理,关闭 Issue"
209
+ },
210
+ "create": {
211
+ "command": "node repo-audit.mjs --feedback '<反馈内容>'",
212
+ "description": "通过 CLI 创建反馈 Issue(自动预填环境信息)"
213
+ },
214
+
215
+ "priorities": [
216
+ { "level": "critical", "sla": "24h", "description": "工具崩溃/数据损坏" },
217
+ { "level": "major", "sla": "72h", "description": "功能严重受损" },
218
+ { "level": "minor", "sla": "1周", "description": "功能部分受损" },
219
+ { "level": "info", "sla": "排期", "description": "建议改进" }
220
+ ]
221
+ },
222
+
223
+ "quick_start": {
224
+ "install": "npm install -g repo-audit-tool",
225
+ "audit": "repo-audit --repo /path/to/repo",
226
+ "json_output": "repo-audit --repo /path/to/repo --format json",
227
+ "scaffold": "node templates/scaffold.mjs --type dsh-plugin --name my-plugin",
228
+ "strict_mode": "repo-audit --repo /path/to/repo --strict",
229
+ "custom_rules": "repo-audit --repo /path/to/repo --rules my-rules.yaml",
230
+ "llm_enhanced": "LLM_API_KEY=sk-xxx repo-audit --repo . --llm-provider deepseek"
231
+ },
232
+
233
+ "changelog": {
234
+ "1.3.0": "反馈修复:yaml_field 行内注释剥离 + fallback_field 通配(SEC-004 兼容 job 级权限);AGENTS-core 来源声明二选一;QUA-004 锁文件消费意图;手册补 --update 存量补齐动线",
235
+ "1.2.3": "package.json 补充 repository 字段,修复 npm provenance E422;完成 Trusted Publisher tag 自动发布",
236
+ "1.2.2": "publish CI 改用 node 22 + 条件升级 npm,修复 EBADENGINE(tag 发布因 1.2.1 已存在未出包)",
237
+ "1.2.1": "README 链接改为绝对 URL(修复 npm 页面 404)",
238
+ "1.2.0": "开源就绪:AGENTS.md、CI/publish workflow、json_field monorepo、fallback_field 数组、英文 README、参数类型校验、占位符扫描"
239
+ }
240
+ }
@@ -0,0 +1,295 @@
1
+ ---
2
+ title: repo-audit Agent Protocol
3
+ version: "1.2.1"
4
+ audience: agent
5
+ format: markdown+metadata
6
+ schema: /SCHEMA.json
7
+ index: /AGENT-INDEX.json
8
+ ---
9
+
10
+ # repo-audit Agent Protocol
11
+
12
+ > 机器可读的操作协议。Agent 直接执行,无需人类解释。
13
+
14
+ ## 1. 工具身份
15
+
16
+ ```json
17
+ {
18
+ "name": "repo-audit",
19
+ "npm": "repo-audit-tool",
20
+ "version": "1.2.1",
21
+ "bin": "repo-audit",
22
+ "language": "JavaScript ESM",
23
+ "runtime": "Node.js >= 18",
24
+ "dependencies": [],
25
+ "license": "MIT",
26
+ "readonly": true
27
+ }
28
+ ```
29
+
30
+ ## 2. 调用协议
31
+
32
+ ### 2.1 基本调用
33
+
34
+ ```
35
+ repo-audit [--repo <path>] [--type <type>] [--format <fmt>] [--output <path>]
36
+ [--llm-provider <p>] [--llm-model <m>] [--strict]
37
+ [--rules <file>] [--dim <domain>] [--feedback <msg>]
38
+ ```
39
+
40
+ ### 2.2 参数
41
+
42
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
43
+ |---|---|---|---|---|
44
+ | `--repo` | string | 否 | `.` | 目标仓库路径 |
45
+ | `--type` | string | 否 | 自动检测 | 强制指定分类 |
46
+ | `--format` | enum | 否 | `both` | `md` / `json` / `both` |
47
+ | `--output` | string | 否 | `<repo>/audit-report/` | 输出目录 |
48
+ | `--llm-provider` | string | 否 | 环境变量 | LLM 协议 |
49
+ | `--llm-model` | string | 否 | 自动 | 模型名称 |
50
+ | `--strict` | bool | 否 | `false` | Critical/Major 即 exit 1 |
51
+ | `--rules` | string[] | 否 | — | 自定义规则 YAML |
52
+ | `--dim` | string[] | 否 | 全部 | 只审计指定维度 |
53
+ | `--feedback` | string | 否 | — | 提交反馈 |
54
+
55
+ ### 2.3 退出码
56
+
57
+ | 码 | 含义 | Agent 应执行 |
58
+ |---|---|---|
59
+ | 0 | 审计通过 | 正常继续 |
60
+ | 1 | Critical/Major 发现 + --strict | 读取 findings 并报告 |
61
+ | 2 | 参数错误 | 修正参数后重试 |
62
+ | 3 | 目标不是 git 仓库 | 提示用户切换到 git 仓库 |
63
+
64
+ ## 3. 输出格式
65
+
66
+ ### 3.1 JSON 报告结构
67
+
68
+ ```json
69
+ {
70
+ "generated_at": "2026-09-06T12:00:00.000Z",
71
+ "audit_type": "dsh-plugin",
72
+ "llm_used": false,
73
+ "metadata": {
74
+ "remote": "https://github.com/org/repo.git",
75
+ "branch": "master",
76
+ "commitCount": 42,
77
+ "fileCount": 117,
78
+ "lastCommit": "2026-09-06 12:00:00 +0800",
79
+ "path": "/path/to/repo"
80
+ },
81
+ "summary": {
82
+ "critical": 0,
83
+ "major": 0,
84
+ "minor": 0,
85
+ "info": 0,
86
+ "pass": 19,
87
+ "total": 19,
88
+ "waived": 0,
89
+ "llmUsed": false
90
+ },
91
+ "findings": [
92
+ {
93
+ "id": "DOC-001",
94
+ "title": "README.md 存在",
95
+ "severity": "critical",
96
+ "domain": "docs",
97
+ "applies_to": ["*"],
98
+ "status": "pass",
99
+ "message": "符合",
100
+ "evidence": "✓ README.md (3.1kB)",
101
+ "hint": null,
102
+ "template_ref": null
103
+ }
104
+ ]
105
+ }
106
+ ```
107
+
108
+ ### 3.2 评分公式
109
+
110
+ ```
111
+ score = 100 - (critical × 25) - (major × 10) - (minor × 3)
112
+ ```
113
+
114
+ | 等级 | 分数 |
115
+ |---|---|
116
+ | A | ≥ 90 |
117
+ | B | ≥ 80 |
118
+ | C | ≥ 70 |
119
+ | D | ≥ 60 |
120
+ | F | < 60 |
121
+
122
+ ### 3.3 发现状态
123
+
124
+ | 状态 | 含义 | Agent 处理 |
125
+ |---|---|---|
126
+ | `pass` | 检查通过 | 忽略 |
127
+ | `fail` | 检查失败 | 读取 `message` + `evidence` + `hint` |
128
+ | `waived` | 已豁免 | 读取 `waived_reason` + `waived_since` |
129
+
130
+ ### 3.4 严重级别
131
+
132
+ | 级别 | 扣分 | Agent 优先级 |
133
+ |---|---|---|
134
+ | `critical` | -25 | P0 — 立即处理 |
135
+ | `major` | -10 | P1 — 优先处理 |
136
+ | `minor` | -3 | P2 — 正常处理 |
137
+ | `info` | 0 | P3 — 参考信息 |
138
+
139
+ ## 4. 标准操作流程
140
+
141
+ ### 4.1 新建仓库后验证
142
+
143
+ ```bash
144
+ repo-audit --repo /path/to/new-repo --format json
145
+ ```
146
+
147
+ Agent 读取 JSON,检查 `summary.grade`:
148
+ - `A` → 通过,报告成功
149
+ - `B/C` → 报告需改进项(列出 fail findings)
150
+ - `D/F` → 警告,建议修复 critical/major 问题
151
+
152
+ ### 4.2 CI 门禁集成
153
+
154
+ ```yaml
155
+ # GitHub Actions 示例
156
+ - name: Audit
157
+ run: repo-audit --repo . --format json --strict
158
+ ```
159
+
160
+ `--strict` 使 Critical/Major 发现返回 exit 1,自动阻断 CI。
161
+
162
+ ### 4.3 自定义规则
163
+
164
+ ```yaml
165
+ # my-rules.yaml
166
+ rules:
167
+ - id: COM-001
168
+ title: "提交信息规范"
169
+ severity: major
170
+ domain: git
171
+ applies_to: ["*"]
172
+ check: commit_message
173
+ params:
174
+ pattern: "^(feat|fix|docs|chore|refactor|test):"
175
+ ```
176
+
177
+ ```bash
178
+ repo-audit --repo . --rules my-rules.yaml
179
+ ```
180
+
181
+ ### 4.4 反馈处理
182
+
183
+ ```bash
184
+ # 检测新反馈
185
+ gh issue list --repo NinjaSln-labs/repo-audit --label audit-feedback --state open --json number,title,createdAt,body
186
+
187
+ # 获取详情
188
+ gh issue view 42 --repo NinjaSln-labs/repo-audit --json title,body,labels
189
+
190
+ # 处理完成
191
+ gh issue close 42 --repo NinjaSln-labs/repo-audit --comment "已处理:修复了 X 问题"
192
+ ```
193
+
194
+ ## 5. 错误处理协议
195
+
196
+ | 错误 | 原因 | Agent 处理 |
197
+ |---|---|---|
198
+ | `目标不是 git 仓库` | 目录无 `.git/` | 提示 `git init` 或切换到正确路径 |
199
+ | `未知参数` | 参数拼写错误 | 检查 `--help` |
200
+ | `LLM 增强失败` | API Key 无效/网络问题 | 降级为非 LLM 模式 |
201
+ | `规则加载失败` | YAML 语法错误 | 报告错误行,不阻断审计 |
202
+ | `分类检测不准` | 文件结构特殊 | 使用 `--type` 强制指定 |
203
+
204
+ ## 6. Agent 决策树
205
+
206
+ ```
207
+ 收到审计请求
208
+ ├─ 有 --repo 参数?
209
+ │ ├─ 否 → 默认当前目录
210
+ │ └─ 是 → 使用指定路径
211
+ ├─ 有 --format 参数?
212
+ │ ├─ json → 只输出 JSON
213
+ │ ├─ md → 只输出 Markdown
214
+ │ └─ both/默认 → 同时输出
215
+ ├─ 有 LLM 配置?
216
+ │ ├─ 是 → 启用 LLM 增强
217
+ │ └─ 否 → 纯规则审计
218
+ ├─ 执行审计
219
+ ├─ 解析 summary
220
+ │ ├─ grade A → 报告通过
221
+ │ ├─ grade B/C → 报告改进项
222
+ │ └─ grade D/F → 警告严重问题
223
+ └─ 输出结果
224
+ ```
225
+
226
+ ## 7. 反馈通道
227
+
228
+ ### 7.1 检测协议
229
+
230
+ ```bash
231
+ # 列出未处理反馈
232
+ gh issue list --repo NinjaSln-labs/repo-audit --label audit-feedback --state open --json number,title,createdAt,body
233
+
234
+ # 获取详情
235
+ gh issue view <NUMBER> --repo NinjaSln-labs/repo-audit --json title,body,labels,createdAt
236
+
237
+ # 关闭已处理
238
+ gh issue close <NUMBER> --repo NinjaSln-labs/repo-audit --comment "已处理:[说明]"
239
+ ```
240
+
241
+ ### 7.2 创建反馈
242
+
243
+ ```bash
244
+ # CLI 方式
245
+ node repo-audit.mjs --feedback "在 xxx 场景下出现 yyy 问题"
246
+
247
+ # API 方式
248
+ gh issue create --repo NinjaSln-labs/repo-audit \
249
+ --title "Feedback: <标题>" \
250
+ --body "<正文>" \
251
+ --label "feedback,audit-feedback"
252
+ ```
253
+
254
+ ### 7.3 处理优先级
255
+
256
+ | 级别 | SLA | 描述 |
257
+ |---|---|---|
258
+ | critical | 24h | 工具崩溃/数据损坏 |
259
+ | major | 72h | 功能严重受损 |
260
+ | minor | 1周 | 功能部分受损 |
261
+ | info | 排期 | 建议改进 |
262
+
263
+ ## 8. 快速参考卡
264
+
265
+ ```bash
266
+ # 安装
267
+ npm install -g repo-audit-tool
268
+
269
+ # 基本审计
270
+ repo-audit --repo /path/to/repo
271
+
272
+ # JSON 输出
273
+ repo-audit --repo /path/to/repo --format json
274
+
275
+ # 严格模式(CI 用)
276
+ repo-audit --repo . --format json --strict
277
+
278
+ # LLM 增强
279
+ LLM_API_KEY=sk-xxx repo-audit --repo . --llm-provider deepseek
280
+
281
+ # 自定义规则
282
+ repo-audit --repo . --rules my-rules.yaml
283
+
284
+ # 指定维度
285
+ repo-audit --repo . --dim security --dim docs
286
+
287
+ # 生成脚手架
288
+ node templates/scaffold.mjs --type dsh-plugin --name my-plugin
289
+
290
+ # 提交反馈
291
+ repo-audit --feedback "问题描述"
292
+
293
+ # 检测反馈
294
+ gh issue list --repo NinjaSln-labs/repo-audit --label audit-feedback --state open
295
+ ```
@@ -0,0 +1,94 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://ninjasln-labs.github.io/repo-audit/SCHEMA.json",
4
+ "title": "repo-audit 审计报告 Schema",
5
+ "description": "repo-audit 工具输出的 JSON 报告格式定义",
6
+ "type": "object",
7
+ "required": ["generated_at", "audit_type", "llm_used", "metadata", "summary", "findings"],
8
+ "properties": {
9
+ "generated_at": {
10
+ "type": "string",
11
+ "format": "date-time",
12
+ "description": "报告生成时间 (ISO 8601)"
13
+ },
14
+ "audit_type": {
15
+ "type": "string",
16
+ "description": "检测到的仓库分类",
17
+ "enum": [
18
+ "dsh-plugin", "python-app", "go-service", "content", "sandbox",
19
+ "archive", "product-oss", "javascript", "typescript", "java",
20
+ "python", "rust", "cpp", "dotnet", "php", "ruby", "unknown"
21
+ ]
22
+ },
23
+ "llm_used": {
24
+ "type": "boolean",
25
+ "description": "是否使用了 LLM 增强"
26
+ },
27
+ "metadata": {
28
+ "type": "object",
29
+ "required": ["remote", "branch", "commitCount", "fileCount", "lastCommit", "path"],
30
+ "properties": {
31
+ "remote": { "type": ["string", "null"], "description": "git remote URL" },
32
+ "branch": { "type": "string", "description": "当前分支" },
33
+ "commitCount": { "type": "number", "description": "commit 总数" },
34
+ "fileCount": { "type": "number", "description": "文件总数" },
35
+ "lastCommit": { "type": "string", "description": "最近 commit 时间" },
36
+ "path": { "type": "string", "description": "仓库路径" }
37
+ }
38
+ },
39
+ "summary": {
40
+ "type": "object",
41
+ "required": ["critical", "major", "minor", "info", "pass", "total", "waived", "llmUsed"],
42
+ "properties": {
43
+ "critical": { "type": "number", "minimum": 0, "description": "Critical 级发现数" },
44
+ "major": { "type": "number", "minimum": 0, "description": "Major 级发现数" },
45
+ "minor": { "type": "number", "minimum": 0, "description": "Minor 级发现数" },
46
+ "info": { "type": "number", "minimum": 0, "description": "Info 级发现数" },
47
+ "pass": { "type": "number", "minimum": 0, "description": "通过的检查数" },
48
+ "total": { "type": "number", "minimum": 1, "description": "总检查数" },
49
+ "waived": { "type": "number", "minimum": 0, "description": "已豁免的检查数" },
50
+ "llmUsed": { "type": "boolean" }
51
+ },
52
+ "description": "汇总统计。评分公式:score = 100 - (critical×25) - (major×10) - (minor×3)。等级:A≥90, B≥80, C≥70, D≥60, F<60"
53
+ },
54
+ "findings": {
55
+ "type": "array",
56
+ "description": "审计发现列表",
57
+ "items": {
58
+ "type": "object",
59
+ "required": ["id", "title", "severity", "domain", "status", "message", "evidence"],
60
+ "properties": {
61
+ "id": {
62
+ "type": "string",
63
+ "description": "规则 ID",
64
+ "pattern": "^(DOC|GIT|QUA|SEC|COM|DEP)-\\d{3}[a-z]?$"
65
+ },
66
+ "title": { "type": "string", "description": "规则标题" },
67
+ "severity": {
68
+ "type": "string",
69
+ "enum": ["critical", "major", "minor", "info"]
70
+ },
71
+ "domain": {
72
+ "type": "string",
73
+ "enum": ["docs", "git", "quality", "security", "compliance", "dependencies"]
74
+ },
75
+ "applies_to": {
76
+ "type": "array",
77
+ "items": { "type": "string" },
78
+ "description": "适用的仓库分类列表,* 表示全部"
79
+ },
80
+ "status": {
81
+ "type": "string",
82
+ "enum": ["pass", "fail", "waived"]
83
+ },
84
+ "message": { "type": "string", "description": "通过: '符合'; 失败: 规则描述" },
85
+ "evidence": { "type": "string", "description": "证据文本" },
86
+ "hint": { "type": ["string", "null"], "description": "修复建议" },
87
+ "template_ref": { "type": ["string", "null"], "description": "模板引用" },
88
+ "waived_reason": { "type": ["string", "null"], "description": "豁免原因" },
89
+ "waived_since": { "type": ["string", "null"], "description": "豁免起始日期" }
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
package/docs/index.html CHANGED
@@ -4,6 +4,31 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>repo-audit 文档</title>
7
+
8
+ <!-- JSON-LD 结构化数据 — AI Agent 可读 -->
9
+ <script type="application/ld+json">
10
+ {
11
+ "@context": "https://schema.org",
12
+ "①type": "SoftwareApplication",
13
+ "name": "repo-audit",
14
+ "url": "https://github.com/NinjaSln-labs/repo-audit",
15
+ "downloadUrl": "https://www.npmjs.com/package/repo-audit-tool",
16
+ "softwareVersion": "1.2.1",
17
+ "applicationCategory": "DeveloperApplication",
18
+ "operatingSystem": "Node.js >= 18",
19
+ "license": "MIT",
20
+ "description": "仓库标准化审计工具 + 工程脚手架生成器(零依赖)",
21
+ "programmingLanguage": "JavaScript ESM",
22
+ "offers": { "@type": "Offer", "price": "0", "priceCurrency": "USD" },
23
+ "documentation": [
24
+ { "name": "AGENT-INDEX.json", "url": "https://ninjasln-labs.github.io/repo-audit/AGENT-INDEX.json", "format": "json" },
25
+ { "name": "SCHEMA.json", "url": "https://ninjasln-labs.github.io/repo-audit/SCHEMA.json", "format": "json-schema" },
26
+ { "name": "AGENT-PROTOCOL.md", "url": "https://ninjasln-labs.github.io/repo-audit/AGENT-PROTOCOL.md", "format": "markdown" },
27
+ { "name": "HUMAN-GUIDE.md", "url": "https://ninjasln-labs.github.io/repo-audit/repo-audit/HUMAN-GUIDE.md", "format": "markdown" },
28
+ { "name": "AGENT-GUIDE.md", "url": "https://ninjasln-labs.github.io/repo-audit/repo-audit/AGENT-GUIDE.md", "format": "markdown" }
29
+ ]
30
+ }
31
+ </script>
7
32
  <style>
8
33
  :root { --bg: #0d1117; --card: #161b22; --border: #30363d; --text: #e6edf3; --muted: #8b949e; --accent: #58a6ff; --accent-hover: #79c0ff; --green: #3fb950; }
9
34
  * { margin: 0; padding: 0; box-sizing: border-box; }
@@ -61,12 +86,13 @@
61
86
  <div class="nav-bar">
62
87
  <a href="https://github.com/NinjaSln-labs/repo-audit" style="font-weight:700;color:var(--text);text-decoration:none;">repo-audit</a>
63
88
  <div class="nav-links">
89
+ <a href="AGENT-INDEX.json">🤖 Agent 索引</a>
90
+ <a href="SCHEMA.json">📐 Schema</a>
91
+ <a href="AGENT-PROTOCOL.md">📖 协议</a>
64
92
  <a href="repo-audit/HUMAN-GUIDE.md">使用手册</a>
65
93
  <a href="repo-audit/AGENT-GUIDE.md">Agent 手册</a>
66
94
  <a href="../AUDIT.md">审计方法论</a>
67
95
  <a href="../BEST-PRACTICES.md">最佳实践</a>
68
- <a href="../REPO-CLASSIFICATION.md">分类检测</a>
69
- <a href="../PUBLISHING.md">发布流程</a>
70
96
  </div>
71
97
  </div>
72
98
 
@@ -90,6 +116,32 @@
90
116
  <div class="stat"><div class="stat-value">0</div><div class="stat-label">npm 依赖</div></div>
91
117
  </div>
92
118
 
119
+ <!-- Agent 入口 -->
120
+ <div class="agent-entry" style="background:#0d2137;border:1px solid #1f6feb;border-radius:8px;padding:1.5rem;margin:2rem 0;">
121
+ <h2 style="color:#58a6ff;font-size:1.3rem;margin-bottom:1rem;">🤖 AI Agent 入口</h2>
122
+ <p style="color:#8b949e;margin-bottom:1rem;">Agent 可读取以下结构化文档,自动理解工具协议、输出格式和调用方式:</p>
123
+ <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:1rem;">
124
+ <div style="background:#161b22;border:1px solid #30363d;border-radius:6px;padding:1rem;">
125
+ <a href="AGENT-INDEX.json" style="color:#58a6ff;text-decoration:none;font-weight:600;">📋 AGENT-INDEX.json</a>
126
+ <p style="color:#8b949e;font-size:0.85rem;margin-top:0.3rem;">机器可读文档索引<br>包含工具参数、退出码、环境变量、文档结构</p>
127
+ </div>
128
+ <div style="background:#161b22;border:1px solid #30363d;border-radius:6px;padding:1rem;">
129
+ <a href="SCHEMA.json" style="color:#58a6ff;text-decoration:none;font-weight:600;">📐 SCHEMA.json</a>
130
+ <p style="color:#8b949e;font-size:0.85rem;margin-top:0.3rem;">JSON Schema 定义<br>用于验证审计报告输出格式</p>
131
+ </div>
132
+ <div style="background:#161b22;border:1px solid #30363d;border-radius:6px;padding:1rem;">
133
+ <a href="AGENT-PROTOCOL.md" style="color:#58a6ff;text-decoration:none;font-weight:600;">📖 AGENT-PROTOCOL.md</a>
134
+ <p style="color:#8b949e;font-size:0.85rem;margin-top:0.3rem;">Agent 操作协议<br>调用方式、输出解析、决策树、错误处理</p>
135
+ </div>
136
+ </div>
137
+ <pre style="margin-top:1rem;background:#0d1117;border:1px solid #30363d;border-radius:6px;padding:1rem;font-size:0.85rem;"><code># Agent 一键获取文档索引
138
+ curl -s https://ninjasln-labs.github.io/repo-audit/AGENT-INDEX.json | jq '.tool.invocation'
139
+
140
+ # 验证审计报告
141
+ jq --argfile schema https://ninjasln-labs.github.io/repo-audit/SCHEMA.json \
142
+ 'empty as $_ | ., (input)' audit-report.json &gt; /dev/null</code></pre>
143
+ </div>
144
+
93
145
  <div class="cards">
94
146
  <div class="card">
95
147
  <h2>📖 人类使用手册</h2>
@@ -191,7 +191,29 @@ cat audit-report/report.json | jq '.findings[] | select(.status=="fail") | .id'
191
191
  # 5. 如有 Critical 发现,阻断生成流程
192
192
  ```
193
193
 
194
- ### 4.2 模板升级后校验
194
+ ### 4.2 存量仓库补齐缺失文档(Issue#3 动线)
195
+
196
+ 审计 fail 后需要补 AGENTS.md / CONTRIBUTING.md 等模板文档时,**优先用 `scaffold --update` 而不是手写**:
197
+
198
+ ```bash
199
+ # 1. 存量仓首次接入(无 .scaffold/lock/)——adopt 模式,零覆盖保证
200
+ node scaffold.mjs --update <repo> --type <type> --dry-run # 先看会落位什么
201
+ node scaffold.mjs --update <repo> --type <type> # 实际执行
202
+
203
+ # 2. 行为:
204
+ # - 仓库缺失的文件(如 AGENTS.md)→ ADDED 直拷
205
+ # - 仓库已有且与模板不同 → .scaffold-merge/ 人工评审区(不覆盖你的内容)
206
+ # - 工作区必须 clean(先 commit/stash)
207
+ # 3. 补齐后重跑审计确认
208
+ node repo-audit.mjs --repo <repo> --format json
209
+ ```
210
+
211
+ 要点:
212
+ - `--update` 对**从未被 scaffold 管理的仓**同样可用(自动 adopt,建立 `.scaffold/lock/`)
213
+ - 手写 AGENTS.md 时,**按来源声明二选一**:无 lock 的仓删除「单源拼装」行、保留「自主维护」行(模板头部已内置两种措辞)
214
+ - `--skip <path>` 可排除不想让模板接管的文件(可多次)
215
+
216
+ ### 4.3 模板升级后校验
195
217
 
196
218
  ```bash
197
219
  # 1. 审计当前状态
@@ -209,7 +231,7 @@ after=$(cat ./audit-after/report.json | jq '.summary')
209
231
  # 如果 after.critical > before.critical → 告警:模板升级引入了问题
210
232
  ```
211
233
 
212
- ### 4.3 CI 门禁集成
234
+ ### 4.4 CI 门禁集成
213
235
 
214
236
  ```yaml
215
237
  # GitHub Actions 示例
@@ -219,7 +241,7 @@ after=$(cat ./audit-after/report.json | jq '.summary')
219
241
  echo "Score: $(jq '.summary | 100 - (.critical * 25) - (.major * 10) - (.minor * 3)' ./.ci-audit/report.json)"
220
242
  ```
221
243
 
222
- ### 4.4 增量维度审计
244
+ ### 4.5 增量维度审计
223
245
 
224
246
  ```bash
225
247
  # 只审计安全(快速)
@@ -232,7 +254,7 @@ node repo-audit.mjs --dim docs --format json
232
254
  node repo-audit.mjs --dim git --dim docs --dim security --dim quality --format json
233
255
  ```
234
256
 
235
- ### 4.5 自定义规则叠加
257
+ ### 4.6 自定义规则叠加
236
258
 
237
259
  ```bash
238
260
  # 创建自定义规则
@@ -507,10 +507,13 @@ node repo-audit.mjs --repo ./my-repo --type python-app
507
507
  | 操作 | 命令序列 |
508
508
  |---|---|
509
509
  | 新建仓库后验证 | `scaffold.mjs --type xxx --name yyy` → `repo-audit.mjs --repo ./yyy` |
510
+ | **存量仓补齐缺失文档** | `scaffold.mjs --update ./zzz --type xxx --dry-run`(预览)→ `scaffold.mjs --update ./zzz`(执行;adopt 模式零覆盖)→ `repo-audit.mjs --repo ./zzz` 复审 |
510
511
  | 模板升级后对比 | `repo-audit.mjs --repo ./zzz --output ./before` → `scaffold.mjs --update ./zzz` → `repo-audit.mjs --repo ./zzz --output ./after` |
511
512
  | CI 门禁 | `repo-audit.mjs --repo . --strict --format json` |
512
513
  | PR 描述附件 | `repo-audit.mjs --repo . --format md --output ./pr-audit` → 附 `pr-audit/report.md` 到 PR |
513
514
 
515
+ > **补 AGENTS.md 提示**(DOC-004 fail 时):优先 `scaffold --update` 补齐(模板头部自带来源声明二选一);确需手写时,无 `.scaffold/lock/` 的仓按「自主维护」措辞写头部,勿照抄「单源拼装」行。
516
+
514
517
  ---
515
518
 
516
519
  ## 十一、操作授权与完成路径
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repo-audit-tool",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "仓库标准化审计工具 + 工程脚手架生成器(零依赖)",
5
5
  "type": "module",
6
6
  "main": "repo-audit.mjs",
@@ -20,6 +20,10 @@
20
20
  "best-practices",
21
21
  "repository"
22
22
  ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/NinjaSln-labs/repo-audit"
26
+ },
23
27
  "engines": {
24
28
  "node": ">=18"
25
29
  },
package/repo-audit.mjs CHANGED
@@ -202,7 +202,48 @@ function countNonHiddenFiles(path) {
202
202
  return count
203
203
  }
204
204
 
205
+ // Issue#2 fix: 定位指定缩进层级下的具名子键(返回行号与缩进;未找到返回 null)
206
+ function findNestedYamlKey(lines, startIdx, baseIndent, key) {
207
+ for (let i = startIdx + 1; i < lines.length; i++) {
208
+ const l = lines[i]
209
+ if (!l.trim() || l.trim().startsWith('#')) continue
210
+ const ind = l.length - l.trimStart().length
211
+ if (ind <= baseIndent) return null
212
+ if (ind !== baseIndent + 2) continue // 只看直接子层(YAML 常规 2 空格缩进)
213
+ const m = l.match(/^\s*(\w[\w\-]*)\s*:\s*(.*)$/)
214
+ if (m && m[1] === key) return { idx: i, indent: ind }
215
+ }
216
+ return null
217
+ }
218
+ // Issue#2 fix: 列出指定父键下一层的所有子键名(通配 * 展开用)
219
+ function listChildKeys(lines, startIdx, baseIndent) {
220
+ const keys = []
221
+ for (let i = startIdx + 1; i < lines.length; i++) {
222
+ const l = lines[i]
223
+ if (!l.trim() || l.trim().startsWith('#')) continue
224
+ const ind = l.length - l.trimStart().length
225
+ if (ind <= baseIndent) break
226
+ if (ind !== baseIndent + 2) continue
227
+ const m = l.match(/^\s*(\w[\w\-]*)\s*:\s*(.*)$/)
228
+ if (m) keys.push(m[1])
229
+ }
230
+ return keys
231
+ }
232
+
205
233
  // P0-3 fix: 嵌套 YAML 路径下钻查找(替代行级正则)
234
+ // Issue#1 fix: 剥离行内注释(# 前须有空白;引号内 # 不算注释——按引号配对状态跳过)
235
+ export function stripYamlComment(s) {
236
+ let str = s
237
+ // 整段以 # 开头(允许前导空白)→ 值为空(父级保持嵌套下钻语义)
238
+ if (/^\s*#/.test(str)) return ''
239
+ // 引号包裹:取第一个配对引号内的内容,引号后的尾注释丢弃
240
+ const q = str.match(/^(\s*)(['"])([\s\S]*?)\2(?:\s+#.*)?$/)
241
+ if (q) return q[3].trim()
242
+ // 无引号:以「空白+#」为注释分隔,截断尾部
243
+ const cut = str.search(/\s#/)
244
+ if (cut !== -1) str = str.slice(0, cut)
245
+ return str.trim()
246
+ }
206
247
  function findNestedYaml(lines, startIdx, baseIndent, segments) {
207
248
  let currentIndent = baseIndent
208
249
  for (let i = startIdx + 1; i < lines.length; i++) {
@@ -213,7 +254,7 @@ function findNestedYaml(lines, startIdx, baseIndent, segments) {
213
254
  const m = l.match(/^\s*(\w[\w\-]*)\s*:\s*(.*)$/)
214
255
  if (m) {
215
256
  const key = m[1]
216
- const valStr = m[2].trim()
257
+ const valStr = stripYamlComment(m[2])
217
258
  const seg = segments[0]
218
259
  if (key === seg) {
219
260
  if (valStr && valStr !== '' && valStr !== '{}') {
@@ -650,7 +691,7 @@ function loadRules(type, customPaths = [], repoPath = null) {
650
691
  grep: { pattern: ['string'] },
651
692
  json_field: { path: ['string'], field: ['string'], fallback_field: ['array', 'string'] },
652
693
  toml_field: { path: ['string'], field: ['string'] },
653
- yaml_field: { path: ['string'], field: ['string'] },
694
+ yaml_field: { path: ['string'], field: ['string'], fallback_field: ['array', 'string'] },
654
695
  directory_exists: { paths: ['array', 'string'] },
655
696
  not_exists: { paths: ['array', 'string'] },
656
697
  glob_count: { pattern: ['string'] },
@@ -1007,7 +1048,7 @@ function runCheck(rule, repoPath, mpj = null) {
1007
1048
  const m = l.match(/^\s*(\w[\w\-]*)\s*:\s*(.*)$/)
1008
1049
  if (m && m[1] === segments[0]) {
1009
1050
  currentIndent = ind
1010
- const valStr = m[2].trim()
1051
+ const valStr = stripYamlComment(m[2])
1011
1052
  if (valStr && valStr !== '' && valStr !== '{}') {
1012
1053
  // 标量值(非嵌套)
1013
1054
  val = valStr
@@ -1028,6 +1069,77 @@ function runCheck(rule, repoPath, mpj = null) {
1028
1069
  passed = false
1029
1070
  evidence = '字段不存在或值不匹配'
1030
1071
  }
1072
+ // Issue#2 fix: yaml_field fallback_field——主字段不匹配时逐个尝试备选字段路径(数组形态)。
1073
+ // 用途:同一语义在不同 YAML 形态下的位置差异(如 id-token: write 可在 workflow 顶层
1074
+ // 或 publish job 级——PyPA 最小化权限模式),任一命中即 pass。
1075
+ // 段内 `*` 为通配(如 jobs.*.permissions.id-token):在该层级所有子键下逐个尝试。
1076
+ if (!passed && params?.fallback_field) {
1077
+ const fbList = Array.isArray(params.fallback_field) ? params.fallback_field : [params.fallback_field]
1078
+ for (const fbField of fbList) {
1079
+ if (!fbField) continue
1080
+ const fbSegments = String(fbField).split('.')
1081
+ const candidates = [] // 每项 {segments} —— 通配展开后的具体路径列表
1082
+ const expandWildcard = (segs) => {
1083
+ const wIdx = segs.indexOf('*')
1084
+ if (wIdx === -1) { candidates.push({ segments: segs }); return }
1085
+ // 找通配段父级的所有子键:先定位父级前缀(逐段下钻收集行号)
1086
+ const lines = content.split('\n')
1087
+ const prefix = segs.slice(0, wIdx)
1088
+ const suffix = segs.slice(wIdx + 1)
1089
+ // 顶层段
1090
+ if (prefix.length === 0) return
1091
+ for (let i = 0; i < lines.length; i++) {
1092
+ const l = lines[i]
1093
+ if (!l.trim() || l.trim().startsWith('#')) continue
1094
+ const m = l.match(/^\s*(\w[\w\-]*)\s*:\s*(.*)$/)
1095
+ if (!m || m[1] !== prefix[0]) continue
1096
+ // 沿 prefix 下钻
1097
+ let curIdx = i, curIndent = l.length - l.trimStart().length
1098
+ let ok = true
1099
+ for (let d = 1; d < prefix.length; d++) {
1100
+ const sub = findNestedYamlKey(lines, curIdx, curIndent, prefix[d])
1101
+ if (!sub) { ok = false; break }
1102
+ curIdx = sub.idx; curIndent = sub.indent
1103
+ }
1104
+ if (!ok) return
1105
+ // 列出 curIndent 下一层的所有子键
1106
+ const childKeys = listChildKeys(lines, curIdx, curIndent)
1107
+ for (const k of childKeys) expandWildcard([...prefix, k, ...suffix])
1108
+ return
1109
+ }
1110
+ }
1111
+ expandWildcard(fbSegments)
1112
+ for (const cand of candidates) {
1113
+ let fbVal = null
1114
+ let fbFound = false
1115
+ try {
1116
+ const lines = content.split('\n')
1117
+ for (let i = 0; i < lines.length; i++) {
1118
+ const l = lines[i]
1119
+ if (!l.trim() || l.trim().startsWith('#')) continue
1120
+ const ind = l.length - l.trimStart().length
1121
+ const m = l.match(/^\s*(\w[\w\-]*)\s*:\s*(.*)$/)
1122
+ if (m && m[1] === cand.segments[0]) {
1123
+ const v = stripYamlComment(m[2])
1124
+ if (v && v !== '' && v !== '{}') { fbVal = v; fbFound = true }
1125
+ else {
1126
+ const sub = findNestedYaml(lines, i, ind, cand.segments.slice(1))
1127
+ if (sub.found) { fbVal = sub.value; fbFound = true }
1128
+ }
1129
+ break
1130
+ }
1131
+ }
1132
+ } catch {}
1133
+ if (fbFound && String(fbVal).trim() === expected) {
1134
+ passed = true
1135
+ const concrete = cand.segments.join('.')
1136
+ evidence = `fallback ${concrete} = ${String(fbVal).trim()}`
1137
+ break
1138
+ }
1139
+ }
1140
+ if (passed) break
1141
+ }
1142
+ }
1031
1143
  break
1032
1144
  }
1033
1145
 
@@ -1539,7 +1651,11 @@ ${message}
1539
1651
  process.exit(hasCritical && strict ? 1 : 0)
1540
1652
  }
1541
1653
 
1542
- main().catch(err => {
1543
- console.error(`✗ 运行时错误: ${err.message}`)
1544
- process.exit(2)
1545
- })
1654
+ // Issue#1 fix: 入口守卫——仅直接作为 CLI 运行时执行主流程;被 import(测试/编程复用)不跑
1655
+ const isDirectRun = import.meta.url === `file://${process.argv[1]}`
1656
+ if (isDirectRun) {
1657
+ main().catch(err => {
1658
+ console.error(`✗ 运行时错误: ${err.message}`)
1659
+ process.exit(2)
1660
+ })
1661
+ }
@@ -54,8 +54,9 @@ rules:
54
54
  - "go.sum"
55
55
  - "requirements.lock"
56
56
  anyOf: true
57
- description: "锁文件应入库以确保可复现构建(BEST-PRACTICES §5.4 验证链)"
58
- note: "无包管理的仓库豁免"
57
+ description: "锁文件应入库以确保可复现构建(BEST-PRACTICES §5.4)——锁文件还须被 CI/验证链实际安装消费(npm ci / pip install -r requirements.lock 等),只入库不安装是装饰性合规;requirements.lock 非 pip 原生锁格式,CI 须显式写明安装它"
58
+ note: "无包管理的仓库豁免;零依赖仓(依赖声明为空,无锁对象)可用 .auditrc.yaml 豁免并注明原因"
59
+ fix_hint: "提交锁文件(package-lock.json / poetry.lock / go.sum / requirements.lock 任一)并确认 CI 安装步骤实际使用它(npm ci / pip install -r …);零依赖仓在 .auditrc.yaml 豁免注明"
59
60
 
60
61
  - id: QUA-005
61
62
  title: "CLAUDE.md 桥接"
@@ -72,8 +72,9 @@ rules:
72
72
  params:
73
73
  path: ".github/workflows/publish.yml"
74
74
  field: "permissions.id-token"
75
+ fallback_field: ["jobs.*.permissions.id-token"]
75
76
  expected: "write"
76
77
  skip_if_no_file: ".github/workflows/publish.yml"
77
- description: "publish workflow 必须请求 id-token: write 权限(OIDC Trusted Publishing)"
78
+ description: "publish workflow 必须请求 id-token: write 权限(OIDC Trusted Publishing)——工作流顶层或 publish job 级任一即可(job 级为 PyPA 推荐的最小化模式)"
78
79
  template_ref: "templates/repo-root/.github/workflows/publish.yml"
79
- fix_hint: "在 workflow 顶部添加 permissions: id-token: write"
80
+ fix_hint: "在 publish workflow 声明 permissions.id-token: write——顶层(permissions: 块内)或仅 publish job(jobs.publish.permissions: 块内)均可;推荐 job 级(最小化,其他 job 不持有 OIDC 权限)"
@@ -1,7 +1,10 @@
1
1
  # AGENTS(AI 协作与工程纪律)
2
2
 
3
- > 本文件由模板**单源拼装**(`common/AGENTS-core.md` + 分类 append)——重复段不要在仓库里手改;
4
- > 改规则先改模板源,再重新生成。人工协作者同样适用本文件全部条款。
3
+ > **来源声明(二选一,按实际来源保留其一,删除另一行)**:
4
+ > - 由 scaffold 生成/更新(仓在 `.scaffold/lock/`):单源拼装(`common/AGENTS-core.md` + 分类 append)——重复段勿手改,改规则先改模板源,再跑 `node scaffold.mjs --update <repo>` 合并。
5
+ > - 手写/移植(无 `.scaffold/lock/`):本文件归本仓库自主维护,直接在仓库内改,单源约束不适用。
6
+ >
7
+ > 人工协作者同样适用本文件全部条款。
5
8
 
6
9
  ## 项目概览
7
10
 
@@ -61,12 +61,17 @@ jobs:
61
61
  # smoke/mount/vitest 为探测式:文件存在才跑,接入即自动进链。
62
62
  run: node scripts/verify.mjs
63
63
  - name: Publish to npm (OIDC trusted publishing)
64
- # 升级 npm:trusted publishing 需 npm CLI >= 11.5.1(含 OIDC 支持)。
64
+ # trusted publishing 需 npm CLI >= 11.5.1(含 OIDC 支持)。
65
+ # 上游 runner Node 自带的 npm 已满足时直接用——不装 npm@latest:
66
+ # 其 engine 门槛会随版本漂移(npm@12 要求 node ^22.22.2,曾致本仓 EBADENGINE),
67
+ # 仅当自带版本过旧时兜底升级到 npm@11(比 latest 门槛低、仍含 OIDC)。
65
68
  # prerelease → dist-tag next(忘加 --tag next 是最常见事故:
66
69
  # 用户 npm install 会装到 prerelease);稳定版 → latest。
67
70
  run: |
68
- npm install -g npm@latest
69
71
  echo "npm version: $(npm --version)"
72
+ if ! npm --version | grep -qE '^(11\.(5\.[1-9]|[6-9]|[0-9]{2})|1[2-9]|2[0-9])'; then
73
+ npm install -g npm@11
74
+ fi
70
75
  VERSION="$(node -p "require('./package.json').version")"
71
76
  if [[ "$VERSION" == *-* ]]; then
72
77
  echo "canary prerelease $VERSION → dist-tag next"
package/HANDOFF.md DELETED
@@ -1,131 +0,0 @@
1
- # HANDOFF — repo-audit 工具(工程交接)
2
-
3
- ## 1. 交接元信息
4
-
5
- - **日期**:2026-09-06
6
- - **交接方**:repo-audit 维护 agent
7
- - **接收方**:继续维护 repo-audit 的 agent / 新 session
8
- - **原因**:里程碑达成(开源发布完成)· 开发仓废弃,转入本开源仓
9
- - **项目一句话**:零依赖 Node.js ESM 仓库标准化审计工具 + 工程脚手架生成器
10
- - **主战场变更**:**本仓 `ninjasin-labs/repo-audit/` 现在是唯一开发与发布位置**;原开发仓 `dsh-ecosystem/research/scaffold-templates/` **已废弃**(历史快照,勿再改)
11
- - **文档入口链**(本仓内):
12
- - 会话记录:`ninjasin-labs/.agents/session.md`(进度权威)
13
- - 人类手册:`docs/repo-audit/HUMAN-GUIDE.md`
14
- - Agent 手册:`docs/repo-audit/AGENT-GUIDE.md`
15
- - 自审报告:`docs/repo-audit/SELF-AUDIT.md`
16
- - 影子回归:`docs/repo-audit/SHADOW-AUDIT-20260906-v3.md`
17
- - **接收方建议动作**:
18
- 1. 读 `ninjasin-labs/.agents/session.md` 了解反馈闭环全貌
19
- 2. 读 `docs/repo-audit/AGENT-GUIDE.md` 了解操作协议
20
- 3. 所有后续开发、迭代、审计验收都在**本仓**完成
21
-
22
- ## 2. 当前状态快照
23
-
24
- ### 版本控制状态
25
-
26
- | 项 | 值 |
27
- |---|---|
28
- | 主仓(本仓) | `ninjasin-labs/repo-audit/`(独立 git 仓) |
29
- | 分支 | master |
30
- | commits | 10(`11eaf65` → `bca65ff` → `cbb7e40` → `de44f20` → `abea615` → `43e9245` → `eea507a` → `45fbfb9` → `b3a2e8f` → `ef967fd` → `4318ae1`) |
31
- | 远端 | **已建** — `https://github.com/NinjaSln-labs/repo-audit`(公开) |
32
- | npm | **已发布** — `repo-audit-tool` v1.2.0(latest) |
33
- | 废弃仓 | `dsh-ecosystem/research/scaffold-templates/`(历史快照,勿改) |
34
-
35
- ### 最近完成(一行式)
36
-
37
- - `4318ae1` docs(release): PUBLISHING.md 更新 — 反映 Trusted Publisher 流程
38
- - `ef967fd` chore(release): 发布 repo-audit-tool@1.2.0 到 npm
39
- - `b3a2e8f` chore(release): 发布准备 — 改名 + bin 可执行 + PUBLISHING.md
40
- - `45fbfb9` fix(engine): C 优化补充 — fallback_field 逗号分隔字符串检测
41
- - `43e9245` fix(ci): 适配 repo-audit — 移除 dsh-demo 模板残留(CI 首次跑通)
42
- - `abea615` fix(engine): json_field monorepo 感知 + fallback_field 数组格式修复
43
- - `de44f20` fix(docs): 补充 AGENTS.md — 修复 CLAUDE.md 悬空引用 + 多文档断链
44
- - `bca65ff` 开源就绪 — 补充工程规范 + 验证链 + 测试(自审计 100/A)
45
- - `11eaf65` repo-audit 开源初始提交
46
- - (开发仓历史,已废弃,仅参考)`e99b504` P6 monorepo / `bcf21d3` E5 豁免 / `053c524` E6 序列化 / `ca01f00` fuyao 假阳性修复
47
-
48
- ### 构建环境状态
49
-
50
- - **零 npm 依赖**,无需 install
51
- - 自审计 **100/A**(19/19 pass)
52
- - 测试:`node --test` 3 用例通过;`node verify.mjs` 4 项通过
53
- - Node ≥18
54
-
55
- ### 占位/未完成边界
56
-
57
- - **json_field 检查器**:仅读仓库根 `package.json`,不递归 workspace(neonforge DOC-003b 残留 minor,非阻塞)
58
- - **GitHub 远端发布未执行**:本地 git 就绪,`gh repo create` / 首次 push 待用户
59
-
60
- ## 3. 下一步与验证点
61
-
62
- ### 立即待办(按优先级)
63
-
64
- 1. ~~**发布到 GitHub 远端**~~ ✅ `NinjaSln-labs/repo-audit` 已公开(2026-09-06)
65
- 2. ~~**json_field workspace 支持**~~ ✅ `abea615` 修复(含 fallback_field 数组格式预存 bug)
66
- 3. ~~**验证 CI**~~ ✅ `43e9245` 修复 dsh-demo 模板残留,CI 首次跑通
67
- 4. ~~**npm 发布**~~ ✅ `repo-audit-tool@1.2.0` 已发布(latest)
68
- 5. **下一步**:npmjs.com 配置 Trusted Publisher → Repository: `NinjaSln-labs/repo-audit`, Workflow: `publish.yml`, Branch: `master`
69
-
70
- ### 外部依赖来源
71
-
72
- - 无 API Key / 凭据依赖(工具可选 LLM 增强,Key 由用户运行时提供,不落仓)
73
- - GitHub 远端发布需用户账号权限
74
-
75
- ### 风险提醒
76
-
77
- - 本仓此前无 .git 时自审计 GIT-001 会 fail;已 commit 后正常
78
- - json_field workspace 盲区影响 monorepo license 一致性检查(minor)
79
-
80
- ## 4. 即时操作
81
-
82
- ```bash
83
- # 本仓自审计
84
- cd ninjasin-labs/repo-audit
85
- node repo-audit.mjs --repo . --format json
86
-
87
- # 验证链
88
- node verify.mjs
89
- node --test
90
-
91
- # 全仓影子回归(ninjasin-labs 下其他仓,可选)
92
- for repo in $(find /home/shadow/ninjasin-labs -maxdepth 3 -name .git -type d | sed 's|/.git$||'); do
93
- node repo-audit.mjs --repo "$repo" --format json 2>/dev/null | grep -o '评分: [0-9]*'
94
- done
95
- ```
96
-
97
- ### 已知坑
98
-
99
- - 引擎对**非 git 仓**输出到 stderr(`✗ 目标不是 git 仓库`),不产生 JSON——verify.mjs 需用 git 仓
100
- - `glob_count` 无法遍历隐藏目录(`.github/`)——CI 检查用 `regex`+`command` 方案而非 glob_count
101
- - `.auditrc.yaml` 解析是简单行解析,`reason` 只取单行且去引号,长 reason 需保持单行
102
-
103
- ## 5. 引用索引
104
-
105
- | 主题 | 权威文档 |
106
- |---|---|
107
- | 会话/进度权威 | `ninjasin-labs/.agents/session.md` |
108
- | 人类使用手册 | `docs/repo-audit/HUMAN-GUIDE.md` |
109
- | Agent 操作协议 | `docs/repo-audit/AGENT-GUIDE.md` |
110
- | AI 协作纪律 | `AGENTS.md` |
111
- | 发布流程 | `PUBLISHING.md` |
112
- | 工具自审 | `docs/repo-audit/SELF-AUDIT.md` |
113
- | 全仓影子回归 | `docs/repo-audit/SHADOW-AUDIT-20260906-v3.md` |
114
- | 反馈闭环(fuyao) | `docs/repo-audit/FEEDBACK-fuyao-nomad.md` |
115
- | 反馈闭环(neonforge) | `docs/repo-audit/FEEDBACK-neonforge.md` |
116
- | 审计方法论 | `AUDIT.md` |
117
- | 最佳实践标准 | `BEST-PRACTICES.md` |
118
- | 分类检测 | `REPO-CLASSIFICATION.md` |
119
- | 核心引擎 | `repo-audit.mjs` |
120
- | 审计规则 | `rules/`(domains + categories) |
121
- | 脚手架生成器 | `templates/scaffold.mjs` |
122
- | 废弃开发仓(仅历史参考) | `dsh-ecosystem/research/scaffold-templates/` |
123
-
124
- ## 6. 维护规则
125
-
126
- - **更新时机**:跨 session / 里程碑 / 用户要求交接时
127
- - **防双源**:本文件只记 delta,文档与 commit 已有内容引用不复制
128
- - **滚动归档**:已确认修复的坑 → `HANDOFF-ARCHIVE/pits.md`,已完成待办 → `HANDOFF-ARCHIVE/done.md`
129
- - **回填约定**:改动规则/引擎后,同步更新 `docs/repo-audit/HUMAN-GUIDE.md` 和 `AGENT-GUIDE.md`
130
- - **脱敏**:不含 API Key/密码/PII(本交接含 `ninjasin-labs` 内部路径,若 push 公开前需注意;或建 .gitignore 排除 HANDOFF.md)
131
- - **主战场**:所有开发在本仓完成,废弃仓不再同步