You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 27c813c
Browse filesBrowse the repository at this point in the historyBrowse files
2.**`--mcp` 是占位**:`scripts/run_check.py:115-123` 的 `mcp_main()` 明文写"MCP server mode not yet wired with official SDK"。文档承诺的 MCP server 入口实际不可用,AI agent 想在不改 shell spawn 的前提下复用 codeguard 失败,只能重新发明。
-`gate-trigger-policy`: Defines when the UserPromptSubmit hook runs the lint gate and which languages it checks; explicitly documents when it stays silent.
20
+
-`mcp-tool-server`: Defines the stdio JSON-RPC surface exposed by `scripts/run_check.py --mcp`, the three tools, their inputs and outputs, and the failure envelope.
### Requirement: The UserPromptSubmit hook SHALL run the lint gate only when intent is commit-like
4
+
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` (`?`, `?`, `么`, `吗`, `如何`, `怎么`, `有没有`, `是不是`, `什么是`, `哪些`).
5
+
6
+
#### Scenario: User asks a question containing a trigger word
7
+
8
+
-**WHEN** the user prompt is `使用过程中的情况` or `Should I commit this?` or `先读项目结构`
9
+
-**THEN** the hook exits 0 with empty stdout; no linter runs
10
+
11
+
#### Scenario: User issues a commit-like imperative
12
+
13
+
-**WHEN** the user prompt is `请帮我 commit` or `commit this now` or `请帮我 push`
14
+
-**THEN** the hook enters the gate path and invokes `run_gate()`
15
+
16
+
#### Scenario: Trigger word followed by question mark is exempt
17
+
18
+
-**WHEN** the user prompt is `commit?` or `要不要 push?` or `should I deploy?`
19
+
-**THEN** the hook exits silently regardless of other QUESTION_MARKERS content
20
+
21
+
### Requirement: The gate SHALL run only languages named in the user message when they can be identified
22
+
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.
23
+
24
+
#### Scenario: User mentions one language explicitly
25
+
26
+
-**WHEN** the user prompt is `请帮我 commit 这次 ruff 改动`
27
+
-**THEN** the gate runs only Python; other detected languages are skipped for this invocation
28
+
29
+
#### Scenario: User mentions no language
30
+
31
+
-**WHEN** the user prompt is `请帮我 commit` with no language token
32
+
-**THEN** the gate runs every language detected by `detect_languages()` (current behavior preserved)
33
+
34
+
### Requirement: Question markers SHALL cover both Chinese and English
35
+
`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.
36
+
37
+
#### Scenario: ASCII question mark without any other marker
38
+
39
+
-**WHEN** the user prompt is `Should I push this?`
40
+
-**THEN** the hook exits silently because `?` is a recognized question marker
### Requirement: The MCP server SHALL expose three tools over stdio JSON-RPC
4
+
`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.
5
+
6
+
#### Scenario: Listing tools at startup
7
+
8
+
-**WHEN** a client sends `tools/list`
9
+
-**THEN** the response enumerates `check_code_style`, `auto_fix`, `list_languages` with their input schemas
10
+
11
+
### Requirement: `check_code_style` SHALL return a structured envelope with full stderr on disk
12
+
`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}`.
13
+
14
+
#### Scenario: One language fails
15
+
16
+
-**WHEN** the path contains a single Python project whose ruff lint fails
17
+
-**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
18
+
19
+
#### Scenario: All languages pass
20
+
21
+
-**WHEN** every linter exits 0
22
+
-**THEN** every entry has `passed=true`, `exit_code=0`, and the log file is either empty or absent (no stderr written)
23
+
24
+
### Requirement: `auto_fix` SHALL run formatters and re-verify
25
+
`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.
26
+
27
+
#### Scenario: Formatter succeeds and lint passes
28
+
29
+
-**WHEN** ruff `--fix` removes unused imports and the re-check passes
30
+
-**THEN**`fixed=true` and the embedded `check_code_style` envelope is all-pass
31
+
32
+
#### Scenario: Formatter succeeds but lint still fails
33
+
34
+
-**WHEN** ruff `--fix` ran but a remaining error is non-fixable
35
+
-**THEN**`fixed=true` and the embedded `check_code_style` envelope contains at least one failing entry
36
+
37
+
### Requirement: `list_languages` SHALL return id + name only
38
+
`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.
39
+
40
+
#### Scenario: Listing all supported languages
41
+
42
+
-**WHEN** the client calls `list_languages`
43
+
-**THEN** the response enumerates every entry in `scripts/languages.json` with exactly two fields (`id`, `name`) per record
0 commit comments