@moon791017/neo-skills 1.1.23 → 1.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -46,8 +46,8 @@ graph TD
46
46
  4. **Plan Edits**: Decompose the task into small, atomic edit plans to avoid large single-turn changes.
47
47
  5. **Minimal Implementation**: Apply minimal code changes while preserving existing comments and public API contracts.
48
48
  6. **Incremental Verification**: Run local test, lint, and build commands immediately after each edit.
49
- 7. **Self-Review**: Inspect diffs and execution logs; if checks fail, read full un-truncated error logs to find the root cause.
50
- 8. **Remediate on Failure**: If verification or self-review fails, return to "Plan Edits / Minimal Implementation" to adjust.
49
+ 7. **Self-Review**: After an AI Agent finishes modifying code, tests, configuration, or scripts, activate `neo-code-review` and review the current uncommitted working tree with `--working-tree`. Inspect diffs and execution logs; if checks fail, read full un-truncated error logs to find the root cause.
50
+ 8. **Remediate on Failure**: If verification or review finds a critical issue, the review scope is unclear, or the skill cannot be loaded, do not declare completion or hand off. Return to "Plan Edits / Minimal Implementation", then rerun verification and `neo-code-review` after each remediation.
51
51
  9. **Handoff upon Pass**: Once all verification sensors pass, present a concise report with empirical proof for handoff.
52
52
 
53
53
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moon791017/neo-skills",
3
- "version": "1.1.23",
3
+ "version": "1.1.24",
4
4
  "type": "module",
5
5
  "description": "Neo Skills: A Universal AI Agent Skills Extension",
6
6
  "homepage": "https://neo-blog-iota.vercel.app/",
@@ -1,81 +1,70 @@
1
1
  ---
2
2
  name: neo-code-review
3
3
  description: >
4
- Use this skill when the user asks for a code review, audit, PR/diff review, bug
5
- risk scan, security/performance/style feedback, or validation of recent changes.
6
- Prioritize actionable findings with file and line evidence.
4
+ Use this skill when the user asks to review or audit source code, a PR, diff, commit,
5
+ or recent changes for bugs, security, performance, tests, compatibility, or
6
+ maintainability. Also use it after an AI agent finishes modifying code to inspect the
7
+ current uncommitted working tree before handoff and report actionable findings with
8
+ file and line evidence.
9
+ compatibility: Requires Python 3.11+ and uv for the Git change helper.
7
10
  ---
8
11
 
9
- # Code Review Specifications
12
+ # Code Review
10
13
 
11
- Apply the Reviewer Pattern. Follow this protocol strictly to systematically, objectively, and constructively review the user's code changes.
14
+ Use the Reviewer workflow. Keep the review read-only and report only evidence-backed, actionable findings.
12
15
 
13
- ---
14
-
15
- ## 1. Perceive Phase
16
+ ## Trigger On
16
17
 
17
- 1. **Identify the Input Source**:
18
- - **Scenario A: Specific files are provided**
19
- - If the user provides specific file paths or directly attaches code snippets in the conversation, use them as the primary targets for review.
20
- - **Scenario B: No files are specified but inside a Git repository**
21
- - If the user asks to "review changes", "review PR", or asks for a review without providing explicit code but the project is a Git repository, **proactively run the helper script** to fetch the changes:
22
- ```bash
23
- uv run skills/neo-code-review/scripts/git-diff-reviewer.py
24
- ```
25
- - To review only the staging area, append the `--staged` argument.
26
- - To review a specific commit range, append the `--commit <range>` argument.
27
- - **Scenario C: No changes detected and not a Git repository**
28
- - If no code input is detected and the environment is not a Git repository, gracefully prompt the user: "No code changes detected. Please provide a specific code snippet or file path." and terminate the review.
18
+ - The user requests a code, PR, diff, commit, security, performance, test, or maintainability review.
19
+ - An AI Agent finishes modifying code, tests, configuration, or scripts before handoff.
29
20
 
30
- 2. **Identify Programming Languages & Frameworks**:
31
- - Identify the programming language (e.g., TypeScript, C#, Python) and relevant frameworks in the code changes to apply language-specific style standards in subsequent phases.
21
+ ## Workflow
32
22
 
33
- ---
23
+ 1. **Collect the review scope**
24
+ - Use the files or code snippets supplied by the user as the primary scope.
25
+ - If no scope is supplied inside a Git repository, run:
26
+ ```bash
27
+ uv run skills/neo-code-review/scripts/git-diff-reviewer.py --working-tree
28
+ ```
29
+ - Use `--staged` for staged-only changes and `--commit <range>` for a commit range.
30
+ - Read surrounding code, related tests, and existing contracts. If no reviewable input exists, report it and stop.
34
31
 
35
- ## 2. Reason Phase
32
+ 2. **Load the rules**
33
+ - Read [review-checklist.md](references/review-checklist.md) before evaluating code.
34
+ - Identify the actual language, framework, and affected behavior from the change. Do not infer unverified rules from filenames.
36
35
 
37
- 1. **Load the Review Checklist**:
38
- - Before evaluating any code, **always read** the external review checklist reference:
39
- [review-checklist.md](file:///Users/ben/Projects/neo-skills/skills/neo-code-review/references/review-checklist.md)
40
-
41
- 2. **Systematically Evaluate Code**:
42
- - Analyze the code logic deeply and compare it against the checklist dimensions: Correctness, Regression Risk, Security, Performance, Data & Concurrency, Test Gaps, SOLID/Design Principles, Logging/Observability, Maintainability, and Style.
43
- - Prioritize evidence-backed findings that create concrete behavioral, security, operational, compatibility, or maintainability risk.
44
- - Filter out **🔴 Critical Issues (Must-fix)** for defects such as requirement breakage, security vulnerabilities, data corruption/loss, broken authorization, severe regressions, or production-impacting reliability failures.
45
- - Classify lower-risk performance, design, logging, test coverage, readability, and maintainability issues under **🟡 Suggestions** when they have a clear reason and actionable remediation.
46
-
47
- ---
36
+ 3. **Analyze risk**
37
+ - Prioritize correctness, regressions, security, data consistency, resource lifetime, concurrency, and high-risk test gaps.
38
+ - `🔴 Critical Issues` contain only security vulnerabilities, data loss, incorrect behavior, authorization bypasses, or major regressions.
39
+ - `🟡 Suggestions` contain only actionable, non-blocking issues with a clear impact and remediation direction.
40
+ - Do not report preferences, unsupported speculation, or checklist items that were not triggered by evidence.
48
41
 
49
- ## 3. Act Phase
42
+ 4. **Produce a concise report**
43
+ - Write in English and preserve file paths and line numbers, such as `src/user.ts:42`.
44
+ - Use this structure. Write `None` when a section has no findings; do not omit the severity sections:
50
45
 
51
- Generate a highly structured and elegant Code Review Report in **Traditional Chinese (Taiwan)**. The report must strictly follow this format:
46
+ ```markdown
47
+ ## 🔍 Review Summary
48
+ - **Status**: `🟢 Ready to deliver`, `🟡 Fix recommended`, `🔴 Delivery blocked`, or `⚪ No reviewable changes`
49
+ - **Scope**: Files or changes that were inspected.
52
50
 
53
- ### 🔍 審查摘要 (Summary)
54
- - **整體評估 (Overall Assessment)**: Provide a brief summary and a clear status rating (e.g., "🔴 需要重大修正後合併" (Needs major changes before merging), "🟡 建議修正後合併" (Recommended to fix before merging), "🟢 結構優良,隨時可合併" (Excellent structure, ready to merge)).
55
- - **變更概述 (Change Overview)**: Briefly describe the main purpose and scope of this change.
51
+ ## 🔴 Critical Issues
52
+ - **Location**: `path:line`
53
+ - **Problem**: Specific behavioral defect.
54
+ - **Impact**: Verifiable consequence.
55
+ - **Fix**: Concrete remediation direction; include code only when it clarifies the fix.
56
56
 
57
- ### 🔴 嚴重問題 (Critical Issues)
58
- *This section must ONLY contain **Must-fix** items (security vulnerabilities, critical logic bugs, or severe flaws that may cause system failure). If none are found, write "無" (None).*
59
- - **[檔案路徑 / 程式碼區段]** (File Path / Code Snippet)
60
- - **問題描述 (Problem Description)**: Clearly state what the problem is.
61
- - **嚴重原因 (Severity Reason)**: Explain *why* this is a critical issue and its potential consequences.
62
- - **修復方案 (Remediation)**: Provide a **concrete corrected code snippet (Code Snippet)** comparing it with the original or showing the fixed version.
57
+ ## 🟡 Suggestions
58
+ - **Location**: `path:line`
59
+ - **Recommendation**: Specific, non-blocking improvement.
63
60
 
64
- ### 🟡 改進建議 (Suggestions)
65
- *Includes suggestions for performance optimization, clean code refactoring, edge-case handling, and comment improvements.*
66
- - **[檔案路徑 / 程式碼區段]** (File Path / Code Snippet)
67
- - **建議事項 (Recommendation)**: How to optimize the code for performance, readability, or maintainability.
68
- - **推薦做法 (Proposed Fix)**: Provide an optimized code example.
69
-
70
- ### 🟢 優秀之處 (Praise) (Optional)
71
- - Highlight exceptionally well-written, elegant, highly readable, or well-tested code sections to encourage best practices.
72
-
73
- ### ❓ 疑問與釐清 (Questions) (Optional)
74
- - Ask objective questions regarding business logic or unexpected implementations to seek clarification from the user.
75
-
76
- ---
61
+ ## 🟢 Strengths
62
+ - List only strengths directly supported by the change.
77
63
 
78
- ## 4. Communication Guidelines
64
+ ## Validation
65
+ - List executed tests, builds, or checks that were not run.
66
+ ```
79
67
 
80
- - **Focus on the Code, not the Coder**: Be constructive, objective, respectful, and humble.
81
- - **Provide Code Snippets**: Always provide a "corrected code example" for identified issues where applicable. Avoid purely theoretical descriptions.
68
+ 5. **Apply the delivery gate**
69
+ - If an automatic review finds `🔴 Critical Issues`, cannot establish the review scope, or cannot load the skill, do not declare completion or hand off.
70
+ - After fixing findings, rerun the required checks and review the changes again.
@@ -1,26 +1,28 @@
1
1
  {
2
2
  "should_trigger": [
3
- "請幫我對這個拉取請求 (PR) 進行代碼審查",
4
- "這段程式碼有沒有潛在的 Bug 或記憶體洩漏?",
5
- "幫我看一下這個 JavaScript 檔案的安全性寫得怎麼樣",
6
- "audit this python script for potential SQL injection or security flaws",
7
- "我們今天的 git 變更寫得如何?執行 code review",
8
- "review my latest git commit changes",
9
- "幫我重構並審查這段 C# 程式碼,看有沒有違反 SOLID 原則",
10
- "這段 TypeScript 程式碼寫得好嗎?有沒有改進空間?",
11
- "檢查一下這段 SQL 查詢的效能,會不會有慢查詢或缺少索引的問題",
12
- "進行靜態代碼分析,指出這個 Go 專案中的問題"
3
+ "Please review this pull request for correctness and regressions",
4
+ "Does this code contain potential bugs or memory leaks?",
5
+ "Review the security of this JavaScript file",
6
+ "Audit this Python script for potential SQL injection or security flaws",
7
+ "Review today's Git changes",
8
+ "Review the changes in my latest Git commit",
9
+ "Refactor and review this C# code for SOLID violations",
10
+ "Is this TypeScript code well designed? What should be improved?",
11
+ "Check this SQL query for performance problems, slow queries, or missing indexes",
12
+ "Run static code analysis and identify problems in this Go project",
13
+ "An AI Agent just finished modifying code. Review the uncommitted changes before handoff"
13
14
  ],
14
15
  "should_not_trigger": [
15
- "如何安裝 git?",
16
- "請幫我寫一個能夠上傳檔案的 FastAPI 後端介面",
17
- "解釋一下什麼是 N+1 查詢問題與如何解決",
18
- "幫我建立一個全新的 React 專案",
19
- "請推薦好用的 Python Linter 工具",
20
- "如何配置 tsconfig.json 來支援 ESM?",
21
- "在 MacOS 上如何部署 Docker 容器?",
22
- "幫我把這段 Python 代碼翻譯成 Rust",
23
- "什麼是 SQL Injection 的原理?",
24
- "幫我產生一份今天的開發進度週報"
16
+ "How do I install Git?",
17
+ "Write a FastAPI endpoint that uploads files",
18
+ "Explain the N+1 query problem and how to solve it",
19
+ "Create a new React project",
20
+ "Recommend a Python linter",
21
+ "How do I configure tsconfig.json for ESM?",
22
+ "How do I deploy a Docker container on macOS?",
23
+ "Translate this Python code into Rust",
24
+ "What is the principle behind SQL injection?",
25
+ "Generate today's development progress report",
26
+ "Run the current project's tests only; do not perform a code review"
25
27
  ]
26
28
  }
@@ -3,27 +3,38 @@
3
3
  "evals": [
4
4
  {
5
5
  "id": 1,
6
- "prompt": "請幫我審查這段 Python 程式碼:\n```python\nimport sqlite3\n\ndef get_user_data(user_id):\n conn = sqlite3.connect('users.db')\n cursor = conn.cursor()\n # 存在 SQL 注入風險與資源未關閉\n query = f\"SELECT * FROM users WHERE id = '{user_id}'\"\n cursor.execute(query)\n return cursor.fetchall()\n```",
7
- "expected_output": "結構化的代碼審查報告。必須明確指出 `user_id` 的 SQL 注入漏洞 (🔴 嚴重問題),指出資料庫連接未釋放的效能/資源問題 (🟡 改進建議),並提供參數化查詢與 `with` 語法糖的修正程式碼範例。報告應全為繁體中文,且包含標準的審查摘要與結構標題。",
6
+ "prompt": "Review this Python code:\n```python\nimport sqlite3\n\ndef get_user_data(user_id):\n conn = sqlite3.connect('users.db')\n cursor = conn.cursor()\n query = f\"SELECT * FROM users WHERE id = '{user_id}'\"\n cursor.execute(query)\n return cursor.fetchall()\n```",
7
+ "expected_output": "A concise English review report. It must identify SQL injection caused by user_id and the unreleased database resources, classify SQL injection as a 🔴 Critical Issue, and provide concrete remediation using a parameterized query and resource management.",
8
8
  "assertions": [
9
- "輸出包含 '🔍 審查摘要'",
10
- "輸出包含 '🔴 嚴重問題'",
11
- "輸出包含 '🟡 改進建議'",
12
- "報告使用繁體中文 (台灣)",
13
- "報告中指出 SQL 注入 (SQL Injection) 漏洞",
14
- "報告中指出資料庫連接或 cursor 未正確釋放/關閉的問題",
15
- "提供使用參數化查詢 (parameterized query) 或 with 語法的修復代碼範例"
9
+ "The output contains '🔍 Review Summary', '🔴 Critical Issues', '🟡 Suggestions', and '## Validation'",
10
+ "The report identifies the SQL injection vulnerability and its verifiable impact",
11
+ "The report identifies the database connection or cursor resource leak",
12
+ "The report classifies SQL injection as a delivery-blocking issue",
13
+ "The report provides remediation using a parameterized query and resource management",
14
+ "The report is written in English and contains no unsupported additional findings"
16
15
  ]
17
16
  },
18
17
  {
19
18
  "id": 2,
20
- "prompt": "審查這段沒有明顯問題的 TypeScript 程式碼,並給出建議:\n```typescript\nexport interface User {\n id: string;\n name: string;\n email: string;\n}\n\nexport function formatUserGreeting(user: User): string {\n return `Hello, ${user.name}! Welcome back.`;\n}\n```",
21
- "expected_output": "給予正面評價的繁體中文審查報告,包含摘要、優秀之處 (🟢 優秀之處),且無嚴重的 Must-fix 問題。可能包含一些關於型別定義或未來擴充性的輕微建議。",
19
+ "prompt": "Review this TypeScript code with no obvious problems and provide recommendations:\n```typescript\nexport interface User {\n id: string;\n name: string;\n email: string;\n}\n\nexport function formatUserGreeting(user: User): string {\n return `Hello, ${user.name}! Welcome back.`;\n}\n```",
20
+ "expected_output": "A concise English review report. 🔴 Critical Issues must be None, the status must not block delivery, and the 🟢 Strengths section should recognize the clear types and simple function design.",
22
21
  "assertions": [
23
- "輸出包含 '🔍 審查摘要'",
24
- "報告中沒有將此代碼列為 '🔴 嚴重問題' (Must-fix)",
25
- "輸出包含 '🟢 優秀之處'",
26
- "報告中讚賞其簡單明瞭、型別定義清晰與具備良好的可讀性"
22
+ "The output contains '🔍 Review Summary', '🔴 Critical Issues', '🟢 Strengths', and '## Validation'",
23
+ "The 🔴 Critical Issues section explicitly says None",
24
+ "The report does not invent security, performance, or test defects",
25
+ "The report recognizes clear type definitions, simple logic, and good readability"
26
+ ]
27
+ },
28
+ {
29
+ "id": 3,
30
+ "prompt": "An AI Agent just finished modifying code, tests, and configuration. Before handoff, run neo-code-review against the current uncommitted working tree, including staged, unstaged, and untracked files. Stop delivery if critical issues are found.",
31
+ "expected_output": "A concise English report scoped to the current uncommitted working tree. It must cite actual file and line evidence and use 🔴 Critical Issues to decide whether delivery is blocked. If no readable changes exist, it must state that no reviewable changes were found without inventing findings.",
32
+ "assertions": [
33
+ "The report confirms that the current uncommitted working tree was reviewed",
34
+ "The report distinguishes the staged, unstaged, and untracked file inputs",
35
+ "The report cites file paths and line numbers or clearly explains why they are unavailable",
36
+ "If 🔴 Critical Issues are found, the status blocks delivery",
37
+ "The report invents no findings when no changes exist"
27
38
  ]
28
39
  }
29
40
  ]
@@ -4,168 +4,232 @@
4
4
  # dependencies = []
5
5
  # ///
6
6
 
7
- """
8
- AI Agentic Git Diff & Code Reader Tool (Non-interactive)
9
- 專為 AI Agent 設計的非互動式程式碼變更與內容擷取腳本。
7
+ """Non-interactive Git change and file reader for AI Agents.
10
8
 
11
- 設計要點:
12
- 1. 嚴禁任何互動式提示詞 (input(), confirm())。
13
- 2. 診斷日誌、錯誤訊息一律寫入 sys.stderr。
14
- 3. 處理結果一律以乾淨的 JSON 結構輸出至 sys.stdout (或寫入指定 --output 檔案)。
9
+ Output rules:
10
+ 1. Never request interactive input.
11
+ 2. Write diagnostics to stderr.
12
+ 3. Write JSON results to stdout or the file supplied with --output.
15
13
  """
16
14
 
17
- import sys
18
15
  import argparse
19
- import subprocess
20
16
  import json
21
17
  import os
22
- from typing import Dict, List, Any
18
+ import subprocess
19
+ import sys
20
+ from typing import Any, Dict, List
21
+
23
22
 
24
23
  def log_diagnostic(message: str) -> None:
25
- """將診斷日誌印至 stderr,避免污染 stdout 的 JSON。"""
24
+ """Write a diagnostic message to stderr."""
26
25
  print(f"[LOG] {message}", file=sys.stderr)
27
26
 
27
+
28
28
  def run_command(cmd: List[str]) -> str:
29
- """執行 shell 命令並返回 stdout,出錯時拋出異常。"""
29
+ """Run a command and return stdout while preserving stderr on failure."""
30
30
  try:
31
31
  result = subprocess.run(
32
32
  cmd,
33
33
  capture_output=True,
34
34
  text=True,
35
- check=True
35
+ check=True,
36
36
  )
37
37
  return result.stdout
38
- except subprocess.CalledProcessError as e:
39
- error_msg = f"命令執行失敗: {' '.join(cmd)}\nStderr: {e.stderr}"
40
- raise RuntimeError(error_msg)
38
+ except subprocess.CalledProcessError as error:
39
+ raise RuntimeError(
40
+ f"Command failed: {' '.join(cmd)}\nStderr: {error.stderr}"
41
+ ) from error
42
+
43
+
44
+ def is_git_repository() -> bool:
45
+ """Return whether the current path is inside a Git worktree."""
46
+ try:
47
+ run_command(["git", "rev-parse", "--is-inside-work-tree"])
48
+ return True
49
+ except RuntimeError:
50
+ return False
41
51
 
42
- def get_git_diff(staged_only: bool = False, commit_range: str = None) -> str:
43
- """根據參數獲取 git diff 內容。"""
52
+
53
+ def has_git_head() -> bool:
54
+ """Return whether the repository has at least one commit."""
55
+ try:
56
+ run_command(["git", "rev-parse", "--verify", "HEAD"])
57
+ return True
58
+ except RuntimeError:
59
+ return False
60
+
61
+
62
+ def get_git_diff(staged_only: bool = False, commit_range: str | None = None) -> str:
63
+ """Get staged changes or a requested commit range."""
44
64
  cmd = ["git", "diff"]
45
65
  if commit_range:
46
66
  cmd.append(commit_range)
47
67
  elif staged_only:
48
68
  cmd.append("--cached")
49
-
50
- log_diagnostic(f"執行 Git 命令: {' '.join(cmd)}")
69
+
70
+ log_diagnostic(f"Running Git command: {' '.join(cmd)}")
51
71
  return run_command(cmd)
52
72
 
73
+
74
+ def get_working_tree_diff() -> str:
75
+ """Get tracked changes after HEAD, including staged and unstaged changes."""
76
+ if has_git_head():
77
+ cmd = ["git", "diff", "HEAD", "--"]
78
+ log_diagnostic(f"Running Git command: {' '.join(cmd)}")
79
+ return run_command(cmd)
80
+
81
+ log_diagnostic("The repository has no HEAD; collecting staged and unstaged changes separately.")
82
+ parts = [
83
+ run_command(["git", "diff", "--cached", "--"]),
84
+ run_command(["git", "diff", "--"]),
85
+ ]
86
+ return "\n".join(part for part in parts if part.strip())
87
+
88
+
89
+ def get_untracked_files() -> List[str]:
90
+ """Get non-ignored untracked files while preserving spaces in paths."""
91
+ output = run_command(["git", "ls-files", "--others", "--exclude-standard", "-z"])
92
+ return [path for path in output.split("\0") if path]
93
+
94
+
53
95
  def read_files_content(paths: List[str]) -> List[Dict[str, str]]:
54
- """讀取指定檔案的完整內容。"""
55
- contents = []
96
+ """Read the contents of the supplied files."""
97
+ contents: List[Dict[str, str]] = []
56
98
  for path in paths:
57
99
  if not os.path.exists(path):
58
- log_diagnostic(f"[警告] 檔案不存在,跳過: {path}")
100
+ log_diagnostic(f"[WARN] File does not exist; skipping: {path}")
59
101
  continue
60
102
  if os.path.isdir(path):
61
- log_diagnostic(f"[警告] 路徑是目錄,跳過: {path}")
103
+ log_diagnostic(f"[WARN] Path is a directory; skipping: {path}")
62
104
  continue
63
-
105
+
64
106
  try:
65
- log_diagnostic(f"讀取檔案內容: {path}")
66
- with open(path, "r", encoding="utf-8", errors="ignore") as f:
67
- contents.append({
68
- "path": path,
69
- "content": f.read()
70
- })
71
- except Exception as e:
72
- log_diagnostic(f"[錯誤] 無法讀取檔案 {path}: {str(e)}")
73
-
107
+ log_diagnostic(f"Reading file: {path}")
108
+ with open(path, "r", encoding="utf-8", errors="ignore") as file:
109
+ contents.append({"path": path, "content": file.read()})
110
+ except OSError as error:
111
+ log_diagnostic(f"[ERROR] Could not read {path}: {error}")
112
+
74
113
  return contents
75
114
 
115
+
76
116
  def parse_args() -> argparse.Namespace:
77
117
  parser = argparse.ArgumentParser(
78
- description="專為 AI Agent 設計的非互動式代碼變更與內容擷取工具。",
79
- epilog="使用範例: uv run git-diff-reviewer.py --staged"
118
+ description="Non-interactive Git change and file reader for AI Agents.",
119
+ epilog="Example: uv run git-diff-reviewer.py --working-tree",
80
120
  )
81
121
  parser.add_argument(
82
- "-i", "--input",
122
+ "-i",
123
+ "--input",
83
124
  nargs="*",
84
- help="選填。指定審查的檔案路徑列表。若未指定,將預設讀取 Git 變更。"
125
+ help="File paths to review; use Git change mode when omitted.",
85
126
  )
86
127
  parser.add_argument(
87
128
  "--staged",
88
129
  action="store_true",
89
- help="僅讀取已暫存 (Staged) 的 Git 變更。"
130
+ help="Read staged Git changes only.",
131
+ )
132
+ parser.add_argument(
133
+ "--working-tree",
134
+ action="store_true",
135
+ help="Read tracked changes after HEAD and non-ignored untracked files.",
90
136
  )
91
137
  parser.add_argument(
92
138
  "--commit",
93
- help="選填。指定 Commit 雜湊值或範圍(例如 HEAD~1..HEAD 或 commit_sha),獲取該範圍內的變更。"
139
+ help="Commit hash or range, for example HEAD~1..HEAD.",
94
140
  )
95
141
  parser.add_argument(
96
- "-o", "--output",
97
- help="選填。將 JSON 結果寫入指定檔案,而非輸出至 stdout。"
142
+ "-o",
143
+ "--output",
144
+ help="Write JSON to this file instead of stdout.",
98
145
  )
99
146
  parser.add_argument(
100
147
  "--dry-run",
101
148
  action="store_true",
102
- help="模擬執行模式,僅在 stderr 輸出分析計畫,不輸出最終的代碼內容。"
149
+ help="Check the selected mode and Git state without reading change content.",
103
150
  )
104
- return parser.parse_args()
151
+ args = parser.parse_args()
152
+
153
+ selectors = [
154
+ bool(args.input),
155
+ args.staged,
156
+ args.working_tree,
157
+ bool(args.commit),
158
+ ]
159
+ if sum(selectors) > 1:
160
+ raise ValueError(
161
+ "The --input, --staged, --working-tree, and --commit options are mutually exclusive."
162
+ )
163
+
164
+ return args
165
+
105
166
 
106
167
  def main() -> None:
107
168
  try:
108
169
  args = parse_args()
109
-
110
- # 準備回傳的結構化資料
111
170
  result: Dict[str, Any] = {
112
171
  "mode": "git-diff",
113
172
  "diff": "",
114
173
  "files": [],
115
- "status": "success"
174
+ "status": "success",
116
175
  }
117
-
118
- # 1. 如果指定了具體檔案
176
+
119
177
  if args.input:
120
178
  result["mode"] = "specific-files"
121
- log_diagnostic(f"指定檔案審查模式。目標檔案數: {len(args.input)}")
179
+ log_diagnostic(f"Specific-file review mode; file count: {len(args.input)}")
122
180
  if not args.dry_run:
123
181
  result["files"] = read_files_content(args.input)
124
-
125
- # 2. 否則,預設使用 Git 變更模式
126
182
  else:
127
- result["mode"] = "git-diff"
128
- log_diagnostic("未指定特定檔案,進入 Git 變更審查模式。")
129
-
130
- # 先檢查是否為 git 專案
131
- try:
132
- run_command(["git", "rev-parse", "--is-inside-work-tree"])
133
- except Exception:
183
+ if not is_git_repository():
134
184
  result["status"] = "error"
135
- result["error_message"] = "當前目錄非 Git 專案,且未指定輸入檔案。"
136
- print(json.dumps(result, indent=2))
137
- log_diagnostic("[錯誤] 當前目錄非 Git 專案。")
185
+ result["error_message"] = "The current path is not a Git repository and no input files were supplied."
186
+ print(json.dumps(result, indent=2, ensure_ascii=False))
187
+ log_diagnostic("[ERROR] The current path is not a Git repository.")
138
188
  sys.exit(1)
139
-
140
- if not args.dry_run:
141
- diff_content = get_git_diff(staged_only=args.staged, commit_range=args.commit)
142
- if not diff_content.strip():
143
- log_diagnostic("未偵測到任何 Git 變更(diff 為空)。")
144
- result["status"] = "empty"
145
- else:
146
- result["diff"] = diff_content
147
-
148
- # 3. 輸出結果
149
- output_str = json.dumps(result, indent=2)
189
+
190
+ if args.working_tree:
191
+ result["mode"] = "working-tree"
192
+ log_diagnostic("Entering working-tree review mode.")
193
+ if not args.dry_run:
194
+ result["diff"] = get_working_tree_diff()
195
+ untracked_files = get_untracked_files()
196
+ result["files"] = read_files_content(untracked_files)
197
+ if not result["diff"].strip() and not untracked_files:
198
+ result["status"] = "empty"
199
+ log_diagnostic("No tracked or untracked changes were detected.")
200
+ else:
201
+ log_diagnostic("Entering Git change review mode.")
202
+ if not args.dry_run:
203
+ diff_content = get_git_diff(
204
+ staged_only=args.staged,
205
+ commit_range=args.commit,
206
+ )
207
+ if not diff_content.strip():
208
+ result["status"] = "empty"
209
+ log_diagnostic("No Git changes were detected.")
210
+ else:
211
+ result["diff"] = diff_content
212
+
213
+ output_str = json.dumps(result, indent=2, ensure_ascii=False)
150
214
  if args.output:
151
- with open(args.output, "w", encoding="utf-8") as f:
152
- f.write(output_str)
153
- log_diagnostic(f"已成功將代碼變更 JSON 寫入至: {args.output}")
215
+ with open(args.output, "w", encoding="utf-8") as file:
216
+ file.write(output_str)
217
+ log_diagnostic(f"Wrote JSON result to: {args.output}")
154
218
  else:
155
- # 乾淨地將結果印在 stdout
156
219
  print(output_str)
157
-
220
+
158
221
  sys.exit(0)
159
-
160
- except Exception as e:
161
- log_diagnostic(f"[致命錯誤] 執行失敗: {str(e)}")
162
- # 確保即使出錯也輸出 JSON 錯誤,使調用端不易崩潰
163
- error_result = {
164
- "status": "error",
165
- "error_message": str(e)
166
- }
167
- print(json.dumps(error_result, indent=2))
222
+ except Exception as error:
223
+ log_diagnostic(f"[FATAL] Execution failed: {error}")
224
+ print(
225
+ json.dumps(
226
+ {"status": "error", "error_message": str(error)},
227
+ indent=2,
228
+ ensure_ascii=False,
229
+ )
230
+ )
168
231
  sys.exit(1)
169
232
 
233
+
170
234
  if __name__ == "__main__":
171
235
  main()