Skip to content

Commit 0038462

Browse files
committed
merge origin/main (v0.10.1) into fix/gate-hardening-from-session-feedback
并行会话先合入 #30(v0.10.0) 与 #32(v0.10.1),本分支叠上去。冲突解法: - 4 份版本 manifest 取 theirs(0.10.1,不回退已发布版本号) - README 双语版本行对齐 0.10.1(#30/#32 未更新该行,顺手修正既存偏差) - scripts/languages.json 自动合并:他们的 find 门禁 -not -path/xargs -r 与本分支 append_files= false ×9 共存(9+13 处断言通过) - hooks/gate_lib.py:scope_cmd 调用双参数并存 (本分支 append_files=append + 上游 full_excludes=not uses_delta_files) - scripts/scope.py:模块 docstring 合并双意图描述 验证:unittest 135/135(含上游新增用例)、run_all 141/0、schema 11 规则
2 parents 877b893 + 7f86fdf commit 0038462

15 files changed

Lines changed: 346 additions & 26 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.3"
12+
"ref": "v0.10.1"
1313
},
1414
"policy": {
1515
"installation": "AVAILABLE",
1616
"authentication": "ON_USE"
1717
},
1818
"category": "Developer Tools",
19-
"version": "0.8.3",
19+
"version": "0.10.1",
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.3/assets/official-logo.png",
21+
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.10.1/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.3/assets/official-logo.png"
25+
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.10.1/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.3+codex.20260922",
3+
"version": "0.10.1+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.3",
8+
"version": "0.10.1",
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: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ AI code that passes lint on first try
6767
|---|---|
6868
| Plugin ID | `partme-codeguard-plugin` |
6969
| Hosts | ZCode, Claude Code, Codex CLI, Kimi Code |
70-
| Current version | `0.8.3` |
70+
| Current version | `0.10.1` |
7171
| ZCode manifest | `.zcode-plugin/plugin.json` |
7272
| Codex manifest | `.codex-plugin/plugin.json` |
7373
| MCP server | Published: stdio server via the official SDK (`check_code_style` / `auto_fix` / `list_languages`); see Quick start |
@@ -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: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ AI 一次写出就过 lint 的代码
6767
|---|---|
6868
| 插件 ID | `partme-codeguard-plugin` |
6969
| 宿主 | ZCode、Claude Code、Codex CLI、Kimi Code |
70-
| 当前版本 | `0.8.3` |
70+
| 当前版本 | `0.10.1` |
7171
| ZCode manifest | `.zcode-plugin/plugin.json` |
7272
| Codex manifest | `.codex-plugin/plugin.json` |
7373
| MCP 服务 | 已发布:官方 SDK stdio 服务(`check_code_style` / `auto_fix` / `list_languages`);见快速开始 |
@@ -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: 43 additions & 2 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,
@@ -414,9 +421,12 @@ def check(lang: str):
414421
break
415422
else:
416423
if scope == "delta":
424+
# files=None(delta 超 50 文件回退全量命令)时同样要剔除构建产物——
425+
# 否则回退路径反而比常规全量门禁更容易扫到 target/ 生成物。
417426
cmd = scope_cmd(
418427
base_cmd, project_root,
419428
files=lang_files if uses_delta_files else None,
429+
full_excludes=not uses_delta_files,
420430
append_files=append,
421431
)
422432
else:
@@ -444,6 +454,9 @@ def check(lang: str):
444454
if stale is not None:
445455
return (lang, None, stale)
446456
detail = _truncate_detail(full or "(linter 无输出)", project_root, lang)
457+
dep_hint = _dependency_resolution_hint(lang, full)
458+
if dep_hint:
459+
detail += f"\n{dep_hint}"
447460
fix = f"自动修复: {' '.join(cmd_def['format'])}" if cmd_def.get("format") else "按上述问题逐项修复"
448461
return (lang, (lang, detail, fix, hint), None)
449462

@@ -501,8 +514,29 @@ def session_state_path() -> Path:
501514
return codeguard_home() / "session_state.json"
502515

503516

504-
def record_skip_event(kind: str) -> None:
505-
"""记录一次绕过(skipGate/逃生门)到会话状态,Stop 汇总时可见。"""
517+
def _dependency_resolution_hint(lang: str, full: str) -> str | None:
518+
"""Java 门禁报依赖解析失败时给行动指引,而不是只留 maven 堆栈尾部。
519+
520+
javadoc:jar 以独立 goal 跑在 reactor 上,sample 类模块常设
521+
maven.install.skip=true,它们的构件不在本地仓——下游模块必然
522+
Could not resolve。没有这行提示,用户看到的是与"该改什么"无关的堆栈。
523+
"""
524+
if lang != "java":
525+
return None
526+
if not _DEP_RESOLUTION_RE.search(full):
527+
return None
528+
return (
529+
"提示:依赖构件不可解析(如 samples 模块 maven.install.skip=true 未入本地仓)。"
530+
"先在仓根执行 mvn install -DskipTests(必要时加 -Dmaven.install.skip=false)再重试门禁。"
531+
)
532+
533+
534+
def record_skip_event(kind: str, project_root: Path | None = None) -> None:
535+
"""记录一次绕过(skipGate/逃生门)到会话状态,Stop 汇总时可见。
536+
537+
除计数外保留最近 20 条明细(时间 + 仓库 + 类型)——豁免必须可回溯:
538+
只有总数时无法回答"哪个仓、什么时候被跳过的"。
539+
"""
506540
state = {}
507541
path = session_state_path()
508542
try:
@@ -514,6 +548,13 @@ def record_skip_event(kind: str) -> None:
514548
meta["count"] = int(meta.get("count", 0)) + 1
515549
kinds = meta.setdefault("kinds", {})
516550
kinds[kind] = int(kinds.get(kind, 0)) + 1
551+
events = meta.setdefault("events", [])
552+
events.append({
553+
"ts": time.strftime("%Y-%m-%dT%H:%M:%S%z"),
554+
"kind": kind,
555+
"repo": project_root.name if project_root else None,
556+
})
557+
del events[:-20]
517558
try:
518559
path.parent.mkdir(parents=True, exist_ok=True)
519560
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
@@ -466,7 +466,7 @@ def main() -> int:
466466
if not roots:
467467
return 0
468468
if any(skip_gate_via_git_config(r) for r in roots):
469-
record_skip_event("skipGate")
469+
record_skip_event("skipGate", roots[0])
470470
return 0
471471

472472
# 按命令链预测实际提交面(纯 commit → 仅 staged;add -A/-a → 三路),

‎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.3",
3+
"version": "0.10.1",
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)