Skip to content

Commit d728cb6

Browse files
committed
fix: 统一 Hook 输出确认与硬门禁故障语义 (v0.14.2)
1 parent b8fa385 commit d728cb6

15 files changed

Lines changed: 142 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.14.1"
12+
"ref": "v0.14.2"
1313
},
1414
"policy": {
1515
"installation": "AVAILABLE",
1616
"authentication": "ON_USE"
1717
},
1818
"category": "Developer Tools",
19-
"version": "0.14.1",
19+
"version": "0.14.2",
2020
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
21-
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.14.1/assets/official-logo.png",
21+
"icon": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.14.2/assets/official-logo.png",
2222
"interface": {
2323
"displayName": "代码规范守卫",
2424
"shortDescription": "Trustworthy code checks and Java impact analysis",
25-
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.14.1/assets/official-logo.png"
25+
"logo": "https://cdn.jsdelivr.net/gh/full-stack-plugins/codeguard-plugin@v0.14.2/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.14.1+codex.20260923",
3+
"version": "0.14.2+codex.20260923",
44
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
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.14.1",
8+
"version": "0.14.2",
99
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
1010
"description_i18n": {
1111
"en": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",

‎docs/current-architecture.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ flowchart TD
3535
| `bin/codeguard`、`scripts/run_check.py`、`scripts/fix.py` | CLI 参数、输出与 MCP stdio 注册 | 不复制扫描器或判定逻辑 |
3636
| `hooks/` | 宿主 JSON、会话事件、通知与退出协议 | 五类 Hook 将检查编排委托应用服务;入口保留旧导入兼容面及 fail-open 协议 |
3737
| `scripts/codeguard/check_application.py`、`language_check.py` | 语言选择、检查与修复请求、MCP 工具分发 | 不导入 MCP SDK;旧 `run_per_language.py` 仅再导出 |
38-
| `startup_application.py`、`session_application.py`、`prompt_application.py`、`git_guard_application.py`、`save_application.py` | 五类 Hook 的盘点、状态消费、软提示、Git 守卫及保存反馈编排 | 返回结构化结果,不打印或调用宿主通知;Hook 控制输出、通知与 fail-open。Stop 在 stdout 刷新后才确认消费;若同时有新统计,为避免丢记录,后续 Stop 可能重复展示旧统计 |
38+
| `startup_application.py`、`session_application.py`、`prompt_application.py`、`git_guard_application.py`、`save_application.py` | 五类 Hook 的盘点、状态消费、软提示、Git 守卫及保存反馈编排 | 返回结构化结果,不打印或调用宿主通知;Hook 控制输出、通知与 fail-open。Stop、软提示与保存反馈在 stdout 刷新后确认状态;Git 已知拦截在输出故障时仍拦截但不缓存。并发或交付重试可能重复反馈,不得丢掉未交付记录 |
3939
| `gate.py`、`gate_checks.py`、`repository_policy.py`、`baseline.py` | Git 门禁、单语言结果、安全规则及有证据的存量比较 | 只有准确基线失败且逐条诊断的文件归属、内容及次数覆盖当前结果才可豁免;基线临时路径映射回被检查文件 |
4040
| `java_build.py`、`java_impact.py`、`java_planning.py` 等 | 构建读取、纯影响闭包、命令选择与环境观察 | 默认保留跳过测试的行为;复杂构建保守扩大检查范围 |
4141
| `cve_reports.py`、`cve_policy.py`、`cve_scanners.py`、`cve.py` | 漏洞报告、阈值、进程适配与复扫编排 | 无有效结构化报告就没有安全通过结论 |
@@ -66,4 +66,4 @@ python3 scripts/vendor/skill_vendor.py check
6666
openspec validate refactor-codeguard-architecture --strict
6767
```
6868

69-
真实 Maven/Gradle 大型项目、联网漏洞数据库、57 种工具链、Windows 与三宿主已安装运行均需要独立证据。临时 Git 快照不是执行沙箱;构建和扫描命令以当前用户权限运行。当前重构的任务进度和本地证据见 `openspec/changes/refactor-codeguard-architecture/verification.md`。v0.13.0 的源码、CI、tag、Release 和市场已核对;其后工作树变更仍需独立发布,宿主安装运行尚未验收。
69+
真实 Maven/Gradle 大型项目、联网漏洞数据库、57 种工具链、Windows 与三宿主已安装运行均需要独立证据。临时 Git 快照不是执行沙箱;构建和扫描命令以当前用户权限运行。当前重构的任务进度和本地证据见 `openspec/changes/refactor-codeguard-architecture/verification.md`。v0.14.1 的源码、CI、tag、Release 和市场已核对;其后工作树变更仍需独立发布,宿主安装运行尚未验收。

‎hooks/post_tool_lint.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ def _main(payload: dict) -> int:
112112
if result.system_message is not None:
113113
message["systemMessage"] = result.system_message
114114
print(json.dumps(message, ensure_ascii=False))
115+
sys.stdout.flush()
115116
result.acknowledge()
116117
if result.notification:
117118
lang, title, message = result.notification

‎hooks/pre_tool_git_guard.py‎

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,26 +79,37 @@ def extract_command(payload: dict) -> str:
7979
def main() -> int:
8080
payload = read_payload()
8181
with session_scope(payload):
82-
if not payload.get("tool_use_id"):
83-
return _main(payload)
84-
key = "pre:" + str(payload["tool_use_id"]) + ":" + extract_command(payload)
85-
cached = completed_event(key)
82+
key = ("pre:" + str(payload["tool_use_id"]) + ":" + extract_command(payload)
83+
if payload.get("tool_use_id") else None)
84+
cached = completed_event(key) if key else None
8685
if cached is not None and cached["code"] == 2:
87-
sys.stdout.write(cached["stdout"])
88-
sys.stderr.write(cached["stderr"])
86+
_deliver(cached["code"], cached["stdout"], cached["stderr"])
8987
return cached["code"]
9088
stdout, stderr = io.StringIO(), io.StringIO()
9189
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
9290
code = _main(payload)
9391
out, err = stdout.getvalue(), stderr.getvalue()
9492
# 只复用阻断结果,硬门放行和未验证永远重跑准确快照。
95-
sys.stdout.write(out)
96-
sys.stderr.write(err)
97-
if code == 2:
93+
delivered = _deliver(code, out, err)
94+
if key and code == 2 and delivered:
9895
record_completed_event(key, code, out, err)
9996
return code
10097

10198

99+
def _deliver(code: int, stdout: str, stderr: str) -> bool:
100+
"""刷新宿主输出后才允许缓存;已知拦截不能因输出故障降为放行。"""
101+
try:
102+
sys.stdout.write(stdout)
103+
sys.stderr.write(stderr)
104+
sys.stdout.flush()
105+
sys.stderr.flush()
106+
except (OSError, UnicodeError, ValueError):
107+
if code == 2:
108+
return False
109+
raise
110+
return True
111+
112+
102113
def _main(payload: dict) -> int:
103114
ensure_user_path()
104115
result = evaluate_git_command(

‎hooks/user_prompt_validator.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ def _main(payload: dict) -> int:
102102
"hookEventName": "UserPromptSubmit",
103103
"additionalContext": result.additional_context,
104104
}}, ensure_ascii=False))
105+
sys.stdout.flush()
105106
result.acknowledge()
106107
return 0
107108

‎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.14.1",
3+
"version": "0.14.2",
44
"description": "Evidence-backed code checks and Git content gates for AI assistants, with Maven/Gradle module impact analysis. Save hooks provide feedback; unverified checks are explicit.",
55
"author": {
66
"name": "Full Stack Skills / PartMe.AI"

‎openspec/changes/refactor-codeguard-architecture/design.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ Stop 的宿主入口先准备原子可读的状态快照,成功写入并刷新
8888
后续 Stop 可能重复展示旧统计,但不会丢掉未展示的新统计。旧直接消费接口继续兼容,
8989
不用于宿主 Stop 交付路径。
9090

91+
同一交付规则也适用于 UserPromptSubmit 和 PostToolUse:入口完成 stdout 刷新后才确认
92+
已完成事件、保存去重和会话统计。PreToolUse 的已知拦截先保留退出码;写入、编码或刷新
93+
故障时不缓存未交付结果,不能通过通用 fail-open 异常处理把明确的拦截改成放行。
94+
这只证明本进程写入管道成功,不能证明宿主最终消费;因此重试允许重复反馈。
95+
9196
事件去重不等于权限缓存。观察 Hook 成功返回后才登记完成,异常允许重试;UPS 有 skipped 时
9297
保守地不登记。硬门禁只重放已完成拒绝,放行、未验证和执行中一律不复用;并发副本允许
9398
重复检查而不能预占后直接放行。保存检查只有已获得结论才记去重,未知可立即重试。

‎openspec/changes/refactor-codeguard-architecture/specs/execution-kernel/spec.md‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262

6363
统计、绕过明细、冷却与审计的读改写 MUST 在进程锁内完成并原子替换文件。宿主提供 session_id 时,统计 MUST 绑定会话与当前 worktree;Stop MUST 只消费该作用域的记录,并与并发写入互斥。无 session_id 时保留旧共享状态兼容,MUST 明示不能证明跨会话隔离。去重 MUST NOT 把未完成或 UNVERIFIED 的检查当成已完成检查。
6464
Stop MUST 在宿主输出成功刷新后才确认消费;输出失败时记录必须保留供重试。若确认前有并发新写入,允许后续 Stop 重复展示旧统计,但不得删除未展示的新记录。
65+
UserPromptSubmit 与 PostToolUse 的已完成事件、文件去重和会话统计 MUST 在相应 stdout 成功刷新后才登记;写入或刷新失败时不得把未交付反馈标记为已交付。PreToolUse 已得到拦截结论时,即使宿主输出失败也 MUST 保留拦截退出码,并且不得缓存该次未交付结果。
6566

6667
#### Scenario: Concurrent writers preserve all increments
6768
- **WHEN** 多个 Hook 进程同时更新同一统计、绕过记录或审计日志
@@ -75,6 +76,14 @@ Stop MUST 在宿主输出成功刷新后才确认消费;输出失败时记录
7576
- **WHEN** Stop 已准备总结但宿主 stdout 写入或刷新失败,或在输出期间有新统计写入
7677
- **THEN** 输出失败时旧统计可在重试中再次展示;并发新统计不得被确认消费误删,允许为了不丢记录而在后续 Stop 重复展示旧统计
7778

79+
#### Scenario: Buffered host feedback fails before delivery
80+
- **WHEN** UserPromptSubmit 或 PostToolUse 已写入反馈,但 stdout 刷新失败
81+
- **THEN** 不登记已完成事件、文件去重或会话统计;下次触发仍可重新检查并交付反馈
82+
83+
#### Scenario: Hard Git block survives host output failure
84+
- **WHEN** PreToolUse 已判定需要拦截,但 stdout 或 stderr 写入或刷新失败
85+
- **THEN** 保持拦截退出码且不缓存该次结果,不能因宿主输出故障改为放行
86+
7887
#### Scenario: Retry follows an unverified save check
7988
- **WHEN** 相同文件未变化,上次保存检查未能获得结论,紧接着再次触发
8089
- **THEN** 再次执行检查,不因此前写入的去重标记而静默跳过

0 commit comments

Comments
 (0)