Skip to content

Commit baf0fe3

Browse files
committed
release: v0.10.0(门禁全量扫描剔除构建产物——find 型 gate 注入 -not -path)
实测(ddd4j-boot 13 分支仓):java 门禁 mvn javadoc:jar 在 target/**/apidocs/ 生成无 shebang 的 javadoc.sh,shell 门禁按源码扫 → SC2148 必红且删了也输(两 gate 步骤并发互相矛盾)。 - scope: _RUFF_FULL_EXCLUDES → 公开 FULL_SCAN_EXCLUDES 单一事实源; full_excludes 时对 find -print0 型命令幂等注入 -not -path(ruff 不变) - gate_lib: delta 超 50 文件回退全量路径同样剔除;java 依赖解析失败 附 mvn install 行动指引;record_skip_event 保留最近 20 条明细 (ts/kind/repo),总数与 kinds 兼容 - validate_languages_json: shellcheck gate/lint 必须钉扎 --severity= (防门禁结论随 cache 版本漂移——老发布版本缺省时 info 级 SC2059/SC2295 也阻塞) - tests/test_full_scan_excludes.py: 14 用例(注入幂等/端到端 javadoc.sh/审计明细/依赖指引/severity 契约);README zh+en;openspec change tests: run_all 141 通过 + 新增 14 用例全绿;ruff 全绿
1 parent 3a9a4f5 commit baf0fe3

15 files changed

Lines changed: 347 additions & 24 deletions

File tree

‎.agents/plugins/marketplace.json‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@
99
"source": {
1010
"source": "url",
1111
"url": "https://github.com/partme-ai/partme-codeguard-plugin.git",
12-
"ref": "v0.8.2"
12+
"ref": "v0.10.0"
1313
},
1414
"policy": {
1515
"installation": "AVAILABLE",
1616
"authentication": "ON_USE"
1717
},
1818
"category": "Developer Tools",
19-
"version": "0.8.2",
19+
"version": "0.10.0",
2020
"description": "Cross-language code lint enforcement for AI coding assistants (ZCode, Claude Code, Codex CLI, Kimi Code): Java, Rust, TypeScript, Python. PostToolUse hook auto-runs the native linter on every AI-written file and blocks on failure in strict mode.",
21-
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.8.2/assets/official-logo.png",
21+
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.10.0/assets/official-logo.png",
2222
"interface": {
2323
"displayName": "代码规范守卫",
2424
"shortDescription": "Make AI-written code pass lint on first try",
25-
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.8.2/assets/official-logo.png"
25+
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.10.0/assets/official-logo.png"
2626
}
2727
}
2828
]

‎.codex-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codeguard",
3-
"version": "0.8.2+codex.20260922",
3+
"version": "0.10.0+codex.20260922",
44
"description": "Cross-language code lint enforcement for AI coding assistants (ZCode, Claude Code, Codex CLI, Kimi Code): Java, Rust, TypeScript, Python. PostToolUse hook auto-runs the native linter on every AI-written file and blocks on failure in strict mode.",
55
"author": {
66
"name": "Full Stack Skills / PartMe.AI",

‎.zcode-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"en": "CodeGuard",
66
"zh-CN": "代码规范检查"
77
},
8-
"version": "0.8.2",
8+
"version": "0.10.0",
99
"description": "Cross-language code lint enforcement for AI coding assistants (ZCode, Claude Code, Codex CLI, Kimi Code): Java, Rust, TypeScript, Python. PostToolUse hook auto-runs the native linter on every AI-written file and blocks on failure in strict mode.",
1010
"description_i18n": {
1111
"en": "Cross-language code lint enforcement. PostToolUse hook auto-runs the language-specific linter on every AI-written file; failed lint blocks further writes when strict_mode is on. Ships ready-to-go .pre-commit-config.yaml templates for Java/Rust/TypeScript/Python.",

‎README.md‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,12 @@ Gate scanning is scoped to **what you are about to change**, decided by git stat
248248
- Project-level `codeguard.json` (repo root) overrides the default:
249249
`{"gate_scope": "repo"}` restores full-repository scanning; `extensions` and
250250
`exclude` customize language detection. Full scans always skip vendor/build
251-
snapshots (immutable supply-chain content).
251+
snapshots (immutable supply-chain content) and build-output directories
252+
(`target`, `dist`, `build`, … — also injected into `find -print0` style gates,
253+
so generated artifacts like maven-javadoc's `javadoc.sh` no longer trip the
254+
shell gate). The >50-file delta fallback to a full command applies the same
255+
exclusions. Java gate failures caused by unresolvable dependencies now carry
256+
an actionable hint (run `mvn install` first) instead of a bare maven stack.
252257

253258
Verdict honesty: a linter crashing with exit 2 (usage/dependency failure) is
254259
reported as **unverified**, never as a lint failure — "cannot verify" is not
@@ -259,7 +264,8 @@ health surface must go red when tooling is absent.
259264

260265
Escape hatch: `git config codeguard.skipGate true` bypasses both the soft and
261266
hard gate for one repository; every bypass is counted and surfaced by the Stop
262-
summary, which also warns when the flag is left enabled. Shared hook state lives
267+
summary, which also warns when the flag is left enabled. The audit keeps the
268+
last 20 events (timestamp + repository + kind). Shared hook state lives
263269
under `CODEGUARD_HOME` (default `~/.codeguard`): session lint statistics,
264270
double-install dedup keys, and the skip audit.
265271

‎README.zh-CN.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,15 +231,20 @@ codeguard:
231231
提交进历史的坏改动,出门时仍会被拦下。
232232
- 项目根的 `codeguard.json` 可覆盖缺省:`{"gate_scope": "repo"}` 恢复全仓扫描;
233233
`extensions` 与 `exclude` 自定义语言识别。全仓扫描始终剔除 vendor/build
234-
快照(供应链不可变内容)。
234+
快照(供应链不可变内容)与构建产物目录(`target`、`dist`、`build` 等,
235+
含 `find -print0` 型 gate——生成物如 maven-javadoc 的 `javadoc.sh` 不再让
236+
shell 门禁误红)。delta 超 50 文件回退全量命令时同样剔除。
237+
Java 门禁报依赖解析失败时附行动指引(`mvn install` 前置说明),而非只留
238+
maven 堆栈尾部。
235239

236240
判定诚实性:linter 以 exit 2(用法/依赖崩溃)退出时按**未验证**上报,绝不计
237241
为 lint 失败——"无法验证"不等于"验证失败",工具崩溃也不会触发自动修复。
238242
exit 127(命令不存在)**按场景有意分流**:交互钩子跳过它(不因工具缺失挡人);
239243
`check`/CI 面按**失败**处理——健康面在工具缺失时就该变红。
240244

241245
逃生门:`git config codeguard.skipGate true` 对单仓同时豁免软门与硬门;每次
242-
绕过都会计数并由 Stop 汇总展示,标志遗留未清时也会提醒。钩子共享状态位于
246+
绕过都会计数并由 Stop 汇总展示,标志遗留未清时也会提醒,审计还保留最近 20
247+
条明细(时间 + 仓库 + 类型)。钩子共享状态位于
243248
`CODEGUARD_HOME`(缺省 `~/.codeguard`):会话 lint 统计、双副本去重键与绕过
244249
审计。
245250

‎hooks/gate_lib.py‎

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,20 @@
1111
import contextlib
1212
import json
1313
import os
14+
import re
1415
import subprocess
1516
import sys
17+
import time
1618
from pathlib import Path
1719

1820
PLUGIN_ROOT = Path(__file__).resolve().parents[1] # hooks/ 的上级 = 插件根
1921
sys.path.insert(0, str(PLUGIN_ROOT / "scripts"))
2022

23+
# maven 依赖解析失败的特征(javadoc:jar 独立 goal 在 reactor 上跑时的典型崩法)
24+
_DEP_RESOLUTION_RE = re.compile(
25+
r"Could not resolve dependencies|Could not find artifact|DependencyResolutionException"
26+
)
27+
2128
from detect_lang import (
2229
LANG_COMMANDS,
2330
detect_language,
@@ -321,7 +328,13 @@ def check(lang: str):
321328
break
322329
else:
323330
if scope == "delta":
324-
cmd = scope_cmd(base_cmd, project_root, files=lang_files if uses_delta_files else None)
331+
# files=None(delta 超 50 文件回退全量命令)时同样要剔除构建产物——
332+
# 否则回退路径反而比常规全量门禁更容易扫到 target/ 生成物。
333+
cmd = scope_cmd(
334+
base_cmd, project_root,
335+
files=lang_files if uses_delta_files else None,
336+
full_excludes=not uses_delta_files,
337+
)
325338
else:
326339
cmd = scope_cmd(base_cmd, project_root, full_excludes=True)
327340
outputs.append(_run_one(cmd, timeout, lang, hint))
@@ -342,6 +355,9 @@ def check(lang: str):
342355
return (lang, None, f"{lang} 工具链异常未验证:exit 2(非 lint 结论){('|' + head[:80]) if head else ''}")
343356
full = "\n".join(seg for seg in ((out or "").rstrip(), (err or "").rstrip()) if seg)
344357
detail = _truncate_detail(full or "(linter 无输出)", project_root, lang)
358+
dep_hint = _dependency_resolution_hint(lang, full)
359+
if dep_hint:
360+
detail += f"\n{dep_hint}"
345361
fix = f"自动修复: {' '.join(cmd_def['format'])}" if cmd_def.get("format") else "按上述问题逐项修复"
346362
return (lang, (lang, detail, fix, hint), None)
347363

@@ -399,8 +415,29 @@ def session_state_path() -> Path:
399415
return codeguard_home() / "session_state.json"
400416

401417

402-
def record_skip_event(kind: str) -> None:
403-
"""记录一次绕过(skipGate/逃生门)到会话状态,Stop 汇总时可见。"""
418+
def _dependency_resolution_hint(lang: str, full: str) -> str | None:
419+
"""Java 门禁报依赖解析失败时给行动指引,而不是只留 maven 堆栈尾部。
420+
421+
javadoc:jar 以独立 goal 跑在 reactor 上,sample 类模块常设
422+
maven.install.skip=true,它们的构件不在本地仓——下游模块必然
423+
Could not resolve。没有这行提示,用户看到的是与"该改什么"无关的堆栈。
424+
"""
425+
if lang != "java":
426+
return None
427+
if not _DEP_RESOLUTION_RE.search(full):
428+
return None
429+
return (
430+
"提示:依赖构件不可解析(如 samples 模块 maven.install.skip=true 未入本地仓)。"
431+
"先在仓根执行 mvn install -DskipTests(必要时加 -Dmaven.install.skip=false)再重试门禁。"
432+
)
433+
434+
435+
def record_skip_event(kind: str, project_root: Path | None = None) -> None:
436+
"""记录一次绕过(skipGate/逃生门)到会话状态,Stop 汇总时可见。
437+
438+
除计数外保留最近 20 条明细(时间 + 仓库 + 类型)——豁免必须可回溯:
439+
只有总数时无法回答"哪个仓、什么时候被跳过的"。
440+
"""
404441
state = {}
405442
path = session_state_path()
406443
try:
@@ -412,6 +449,13 @@ def record_skip_event(kind: str) -> None:
412449
meta["count"] = int(meta.get("count", 0)) + 1
413450
kinds = meta.setdefault("kinds", {})
414451
kinds[kind] = int(kinds.get(kind, 0)) + 1
452+
events = meta.setdefault("events", [])
453+
events.append({
454+
"ts": time.strftime("%Y-%m-%dT%H:%M:%S%z"),
455+
"kind": kind,
456+
"repo": project_root.name if project_root else None,
457+
})
458+
del events[:-20]
415459
try:
416460
path.parent.mkdir(parents=True, exist_ok=True)
417461
path.write_text(json.dumps(state, ensure_ascii=False), encoding="utf-8")

‎hooks/pre_tool_git_guard.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ def main() -> int:
298298
if not roots:
299299
return 0
300300
if any(skip_gate_via_git_config(r) for r in roots):
301-
record_skip_event("skipGate")
301+
record_skip_event("skipGate", roots[0])
302302
return 0
303303

304304
# 每个被操作的仓库独立跑:linter 门禁 + 提交内容安全检查

‎hooks/user_prompt_validator.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ def main() -> int:
172172
if skip_gate_via_git_config(project_root):
173173
# 软门禁与硬门禁共用同一条仓库级豁免:此前 UPS 不认 skipGate,
174174
# 出现过"硬门放行、软门仍喊禁止提交"的自相矛盾。
175-
record_skip_event("skipGate")
175+
record_skip_event("skipGate", project_root)
176176
return 0
177177

178178
cfg = load_user_config()

‎kimi.plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codeguard",
3-
"version": "0.8.2",
3+
"version": "0.10.0",
44
"description": "Cross-language code lint enforcement for AI coding assistants (ZCode, Claude Code, Codex CLI, Kimi Code): Java, Rust, TypeScript, Python. PostToolUse hook auto-runs the native linter on every AI-written file and blocks on failure in strict mode.",
55
"author": {
66
"name": "Full Stack Skills / PartMe.AI"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# 2026-09-22-gate-full-scan-excludes
2+
3+
## Why
4+
5+
ddd4j-boot 13 分支仓实测:java 门禁 `mvn javadoc:jar` 在 `target/**/apidocs/`
6+
生成无 shebang 的 `javadoc.sh`,shell 门禁的 find 把它当源码扫(SC2148),
7+
commit/push 门禁必红且删了也输(java lint 并发再生成)——两个 gate 步骤
8+
互相矛盾。排除基建已存在但只物化 ruff:`scope_cmd(full_excludes=True)`
9+
仅对 `ruff` 追加 `--exclude`,`find -print0` 型 gate 原样透传。同批实测
10+
还发现:老发布版本 shellcheck gate 缺 `--severity` 钉扎,info 级发现
11+
(SC2059/SC2295)也阻塞;skipGate 豁免只有总数没有明细。
12+
13+
## What Changes
14+
15+
- `scope.py`:`_RUFF_FULL_EXCLUDES` → 公开的 `FULL_SCAN_EXCLUDES`(单一
16+
事实源);新增 `_inject_find_excludes`——`full_excludes=True` 时给
17+
`find … -print0` 型命令注入 `-not -path '*/<dir>/*'`,幂等,ruff 路径不变。
18+
- `gate_lib.py`:delta 超 50 文件回退全量命令的路径补 `full_excludes=True`
19+
(回退路径此前比常规全量门禁更容易扫到 target/);java 门禁依赖解析
20+
失败(Could not resolve / Could not find artifact)追加行动指引;
21+
`record_skip_event` 增加最近 20 条明细(时间 + 仓库 + 类型),总数与
22+
kinds 字段保持兼容。
23+
- `validate_languages_json.py`:新契约——gate/lint 中调用 shellcheck 必须
24+
钉扎 `--severity=`(防"门禁结论随 cache 版本漂移"回归)。
25+
26+
## Impact
27+
28+
- Affected specs: `language-gate-commands`(gate 命令可执行性 + 一致性契约)
29+
- 受益场景:任何 Maven/Gradle 项目(构建产物不再引发 shell/java 门禁互斥)、
30+
skipGate 豁免可回溯、依赖解析失败有出路指引。

0 commit comments

Comments
 (0)