Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ None.

- `hooks/user_prompt_validator.py`:触发判定与语言选择逻辑改动;外部行为变化仅在误触发场景(更少误触发为正向变化)。
- `scripts/run_check.py`:新增官方 SDK 依赖(`mcp` 包需写入 `requirements.txt` 或类似清单),新增 `out/.codeguard-last.log` 落盘逻辑,删除占位 `mcp_main` 分支。
- 新建根 `requirements.txt` 声明 `mcp>=1.0`(本仓当前没有任何 requirements 文件;`mcp` 1.26.0 已在开发环境安装,CI 需显式安装)。
- 新建根 `requirements.txt` 声明 `mcp>=1.0,<2`(2.x 更改了装饰器 API;本仓此前无 requirements 文件,CI 显式安装)。
- 不修改 vendored 技能(codeguard-* 走 vendor 流程);不修改 marketplace 清单。
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

## 7. Release

- [ ] 7.1 `node scripts/bump-plugin.mjs codeguard minor` (0.6.6 → 0.7.0; MCP server is a new feature).
- [ ] 7.2 Sync marketplace manifest + hub catalog.
- [ ] 7.3 Push, confirm CI green, tag v0.7.0, GitHub Release.
- [ ] 7.4 `openspec archive 2026-09-22-fix-gate-trigger-and-mcp`.
- [x] 7.1 Bump minor 0.6.8 → 0.7.0 (MCP server is a new feature; worktree depth broke the hub resolver so manifests were completed manually: 4 manifests + marketplace ref/icon/logo pins + README rows).
- [x] 7.2 Sync marketplace manifest + hub catalog (repo pins v0.7.0; hub chain landed as `release: codeguard 0.7.0` + README row alignment).
- [x] 7.3 Push, confirm CI green (PR #21 feature, PR #24 release), tag v0.7.0 at dbc133a, GitHub Release published (README row follow-up at main 0e84186).
- [x] 7.4 `openspec archive 2026-09-22-fix-gate-trigger-and-mcp`(delta specs 已并入 openspec/specs:gate-trigger-policy +3、mcp-tool-server +4)。
44 changes: 44 additions & 0 deletions openspec/specs/gate-trigger-policy/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# gate-trigger-policy Specification

## Purpose
TBD - created by archiving change 2026-09-22-fix-gate-trigger-and-mcp. Update Purpose after archive.
## Requirements
### Requirement: The UserPromptSubmit hook SHALL run the lint gate only when intent is commit-like
The `UserPromptSubmit` hook MUST evaluate the user's prompt for commit intent using word-boundary matching of trigger words (`commit|push|deploy|发布|部署`) and a separate action-verb check. The hook SHALL exit silently when either (a) no trigger word is present, (b) the only trigger occurrence is followed by `?`, or (c) a trigger word appears in an interrogative sentence identified by `QUESTION_MARKERS` (`?`, `?`, `么`, `吗`, `如何`, `怎么`, `有没有`, `是不是`, `什么是`, `哪些`).

#### Scenario: User asks a question containing a trigger word

- **WHEN** the user prompt is `使用过程中的情况` or `Should I commit this?` or `先读项目结构`
- **THEN** the hook exits 0 with empty stdout; no linter runs

#### Scenario: User issues a commit-like imperative

- **WHEN** the user prompt is `请帮我 commit` or `commit this now` or `请帮我 push`
- **THEN** the hook enters the gate path and invokes `run_gate()`

#### Scenario: Trigger word followed by question mark is exempt

- **WHEN** the user prompt is `commit?` or `要不要 push?` or `should I deploy?`
- **THEN** the hook exits silently regardless of other QUESTION_MARKERS content

### Requirement: The gate SHALL run only languages named in the user message when they can be identified
When the trigger fires, the hook MUST extract candidate language ids from the user prompt using case-insensitive token matching against `scripts/languages.json` ids. When the intersection is non-empty, the gate SHALL run only that subset. When the intersection is empty, the gate SHALL fall back to the existing `detect_languages()` behavior.

#### Scenario: User mentions one language explicitly

- **WHEN** the user prompt is `请帮我 commit 这次 ruff 改动`
- **THEN** the gate runs only Python; other detected languages are skipped for this invocation

#### Scenario: User mentions no language

- **WHEN** the user prompt is `请帮我 commit` with no language token
- **THEN** the gate runs every language detected by `detect_languages()` (current behavior preserved)

### Requirement: Question markers SHALL cover both Chinese and English
`QUESTION_MARKERS` MUST include the ASCII `?` in addition to the existing Chinese markers, so that an English prompt ending with `?` is recognized as a question even without other markers.

#### Scenario: ASCII question mark without any other marker

- **WHEN** the user prompt is `Should I push this?`
- **THEN** the hook exits silently because `?` is a recognized question marker

47 changes: 47 additions & 0 deletions openspec/specs/mcp-tool-server/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# mcp-tool-server Specification

## Purpose
TBD - created by archiving change 2026-09-22-fix-gate-trigger-and-mcp. Update Purpose after archive.
## Requirements
### Requirement: The MCP server SHALL expose three tools over stdio JSON-RPC
`scripts/run_check.py --mcp` MUST start an stdio JSON-RPC server using the official `mcp` Python SDK and register exactly three tools: `check_code_style`, `auto_fix`, and `list_languages`. The server MUST NOT take any other CLI flag in MCP mode.

#### Scenario: Listing tools at startup

- **WHEN** a client sends `tools/list`
- **THEN** the response enumerates `check_code_style`, `auto_fix`, `list_languages` with their input schemas

### Requirement: `check_code_style` SHALL return a structured envelope with full stderr on disk
`check_code_style(path, languages?)` MUST run the configured linters, write the full stderr of any failing invocation to `<log_dir>/.codeguard-last.log` (default `<project>/out/.codeguard-last.log`), and return a JSON envelope with one entry per language: `{language, passed: bool, exit_code: int, stderr_path: str, log_path: str}`.

#### Scenario: One language fails

- **WHEN** the path contains a single Python project whose ruff lint fails
- **THEN** the envelope contains one entry with `passed=false`, `exit_code` from ruff, `stderr_path` pointing at the on-disk log, and `log_path` echoing the same path

#### Scenario: All languages pass

- **WHEN** every linter exits 0
- **THEN** every entry has `passed=true`, `exit_code=0`, and the log file is either empty or absent (no stderr written)

### Requirement: `auto_fix` SHALL run formatters and re-verify
`auto_fix(path, languages?)` MUST invoke the per-language formatter chain (`format` from `scripts/languages.json`) and then re-run `check_code_style` on the same scope before returning. The response envelope MUST contain both `fixed: bool` (whether any file was modified) and the `check_code_style` envelope for the post-fix re-check.

#### Scenario: Formatter succeeds and lint passes

- **WHEN** ruff `--fix` removes unused imports and the re-check passes
- **THEN** `fixed=true` and the embedded `check_code_style` envelope is all-pass

#### Scenario: Formatter succeeds but lint still fails

- **WHEN** ruff `--fix` ran but a remaining error is non-fixable
- **THEN** `fixed=true` and the embedded `check_code_style` envelope contains at least one failing entry

### Requirement: `list_languages` SHALL return id + name only
`list_languages()` MUST return a JSON array of `{id, name}` objects from `scripts/languages.json`, omitting the rest of each language record (lint command, format command, install hint, etc.) so internal commands are not exposed as part of the MCP surface.

#### Scenario: Listing all supported languages

- **WHEN** the client calls `list_languages`
- **THEN** the response enumerates every entry in `scripts/languages.json` with exactly two fields (`id`, `name`) per record

Loading