moai-adk 0.6.3__py3-none-any.whl → 0.8.0__py3-none-any.whl

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.
Files changed (31) hide show
  1. moai_adk/core/config/__init__.py +13 -0
  2. moai_adk/core/config/migration.py +113 -0
  3. moai_adk/core/project/phase_executor.py +8 -3
  4. moai_adk/templates/.claude/agents/alfred/cc-manager.md +1 -1
  5. moai_adk/templates/.claude/agents/alfred/debug-helper.md +2 -2
  6. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +2 -2
  7. moai_adk/templates/.claude/agents/alfred/git-manager.md +2 -2
  8. moai_adk/templates/.claude/agents/alfred/implementation-planner.md +2 -2
  9. moai_adk/templates/.claude/agents/alfred/project-manager.md +6 -6
  10. moai_adk/templates/.claude/agents/alfred/quality-gate.md +2 -2
  11. moai_adk/templates/.claude/agents/alfred/skill-factory.md +7 -7
  12. moai_adk/templates/.claude/agents/alfred/spec-builder.md +2 -2
  13. moai_adk/templates/.claude/agents/alfred/tag-agent.md +2 -2
  14. moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +2 -2
  15. moai_adk/templates/.claude/agents/alfred/trust-checker.md +2 -2
  16. moai_adk/templates/.claude/commands/alfred/0-project.md +54 -37
  17. moai_adk/templates/.claude/commands/alfred/1-plan.md +104 -16
  18. moai_adk/templates/.claude/commands/alfred/2-run.md +28 -16
  19. moai_adk/templates/.claude/commands/alfred/3-sync.md +38 -21
  20. moai_adk/templates/.claude/hooks/alfred/core/project.py +145 -13
  21. moai_adk/templates/.claude/hooks/alfred/handlers/session.py +90 -20
  22. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +1 -1
  23. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +1 -1
  24. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +1 -1
  25. moai_adk/templates/.moai/config.json +4 -0
  26. moai_adk/templates/CLAUDE.md +67 -1
  27. {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/METADATA +1 -1
  28. {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/RECORD +31 -29
  29. {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/WHEEL +0 -0
  30. {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/entry_points.txt +0 -0
  31. {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -21,7 +21,7 @@ allowed-tools:
21
21
  ---
22
22
 
23
23
  # 🏗️ MoAI-ADK Step 1: Establish a plan (Plan) - Always make a plan first and then proceed.
24
- > Interactive prompts rely on `Skill("moai-alfred-interactive-questions")` so AskUserQuestion renders TUI selection menus for user surveys and approvals.
24
+ > **Note**: Interactive prompts use `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)` for TUI selection menus. The skill is loaded on-demand when user interaction is required.
25
25
 
26
26
  ## 🎯 Command Purpose
27
27
 
@@ -29,6 +29,22 @@ allowed-tools:
29
29
 
30
30
  **Plan for**: $ARGUMENTS
31
31
 
32
+ ## 🤖 CodeRabbit AI Integration (Local Only)
33
+
34
+ This local environment includes CodeRabbit AI review integration for SPEC documents:
35
+
36
+ **Automatic workflows:**
37
+ - ✅ SPEC review: CodeRabbit analyzes SPEC metadata and EARS structure
38
+ - ✅ GitHub Issue sync: SPEC files automatically create/update GitHub Issues
39
+ - ✅ Auto-approval: Draft PRs are approved when quality meets standards (80%+)
40
+ - ✅ SPEC quality validation: Checklist for metadata, structure, and content
41
+
42
+ **Scope:**
43
+ - 🏠 **Local environment**: Full CodeRabbit integration with auto-approval
44
+ - 📦 **Published packages**: Users get GitHub Issue sync only (no CodeRabbit)
45
+
46
+ > See `.coderabbit.yaml` for detailed review rules and SPEC validation checklist
47
+
32
48
  ## 💡 Planning philosophy: "Always make a plan first and then proceed."
33
49
 
34
50
  `/alfred:1-plan` is a general-purpose command that **creates a plan**, rather than simply “creating” a SPEC document.
@@ -126,14 +142,28 @@ Invoking the Task tool (Explore agent):
126
142
  Call the Task tool:
127
143
  - subagent_type: "spec-builder"
128
144
  - description: "Analyze the plan and establish a plan"
129
- - prompt: "Please analyze the project document and suggest SPEC candidates.
130
- Run in analysis mode, and must include the following:
131
- 1. In-depth analysis of product/structure/tech.md
132
- 2. Identify SPEC candidates and Determine priorities
133
- 3. Design EARS structure
134
- 4. Wait for user approval
135
- User input: $ARGUMENTS
136
- (Optional) Explore results: $EXPLORE_RESULTS"
145
+ - prompt: """You are spec-builder agent.
146
+
147
+ LANGUAGE CONFIGURATION:
148
+ - conversation_language: {{CONVERSATION_LANGUAGE}}
149
+ - language_name: {{CONVERSATION_LANGUAGE_NAME}}
150
+
151
+ CRITICAL INSTRUCTION:
152
+ All SPEC documents and analysis must be generated in conversation_language.
153
+ - If conversation_language is 'ko' (Korean): Generate ALL analysis, plans, and SPEC documents in Korean
154
+ - If conversation_language is 'ja' (Japanese): Generate ALL analysis, plans, and SPEC documents in Japanese
155
+ - If conversation_language is other language: Follow the specified language
156
+
157
+ TASK:
158
+ Please analyze the project document and suggest SPEC candidates.
159
+ Run in analysis mode, and must include the following:
160
+ 1. In-depth analysis of product/structure/tech.md
161
+ 2. Identify SPEC candidates and Determine priorities
162
+ 3. Design EARS structure
163
+ 4. Wait for user approval
164
+
165
+ User input: $ARGUMENTS
166
+ (Optional) Explore results: $EXPLORE_RESULTS"""
137
167
  ```
138
168
 
139
169
  ### Plan analysis progress
@@ -156,7 +186,7 @@ Call the Task tool:
156
186
 
157
187
  ### User verification steps
158
188
 
159
- After reviewing your implementation plan, Alfred invokes `Skill("moai-alfred-interactive-questions")` to present the following options:
189
+ After reviewing your implementation plan, Alfred invokes `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)` to present the following options:
160
190
  - **"Go"** or **"Start"**: Start writing the plan as planned
161
191
  - **"Modify [Content]"**: Request modifications to the plan
162
192
  - **"Stop"**: Stop writing the plan
@@ -165,21 +195,37 @@ After reviewing your implementation plan, Alfred invokes `Skill("moai-alfred-int
165
195
 
166
196
  ## 🚀 STEP 2: Create plan document (after user approval)
167
197
 
168
- After user approval (collected via `Skill("moai-alfred-interactive-questions")`), call the spec-builder and git-manager agents using the **Task tool**.
198
+ After user approval (collected via `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)`), call the spec-builder and git-manager agents using the **Task tool**.
169
199
 
170
200
  ### ⚙️ How to call an agent
171
201
 
172
202
  ```
173
203
  1. Call spec-builder (create plan):
174
204
  - subagent_type: "spec-builder"
175
- - description: "Create SPEC document"
176
- - prompt: "Please fill out the SPEC document according to the plan approved in STEP 1.
177
- Create a specification for the EARS structure."
205
+ - description: "Create SPEC document"
206
+ - prompt: """You are spec-builder agent.
207
+
208
+ LANGUAGE CONFIGURATION:
209
+ - conversation_language: {{CONVERSATION_LANGUAGE}}
210
+ - language_name: {{CONVERSATION_LANGUAGE_NAME}}
211
+
212
+ CRITICAL INSTRUCTION:
213
+ ALL SPEC documents MUST be generated in conversation_language:
214
+ - spec.md: Full document in conversation_language
215
+ - plan.md: Full document in conversation_language
216
+ - acceptance.md: Full document in conversation_language
217
+
218
+ YAML frontmatter and @TAG identifiers MUST remain in English.
219
+ Code examples and technical keywords can be mixed (code in English, narrative in user language).
220
+
221
+ TASK:
222
+ Please fill out the SPEC document according to the plan approved in STEP 1.
223
+ Create a specification for the EARS structure."""
178
224
 
179
225
  2. Invoke git-manager (Git task):
180
226
  - subagent_type: "git-manager"
181
- - description: "Create Git branch/PR"
182
- - prompt: "After completing the plan, please create a branch and Draft PR."
227
+ - description: "Create Git branch/PR"
228
+ - prompt: "After completing the plan, please create a branch and Draft PR."
183
229
  ```
184
230
 
185
231
  ## function
@@ -549,6 +595,48 @@ The `git-manager` agent does **all at once** after the SPEC is complete:
549
595
  3. **Initial commit**: Commit SPEC document and create tags
550
596
  4. **Remote Sync**: Apply synchronization strategy for each mode
551
597
 
598
+ ### Phase 3.5: CodeRabbit SPEC Review (Local Only)
599
+
600
+ **After Draft PR is created, CodeRabbit automatically:**
601
+
602
+ ```bash
603
+ echo "🤖 Waiting for CodeRabbit SPEC review..."
604
+
605
+ # CodeRabbit triggers automatically on Draft PR creation
606
+ # Review includes:
607
+ # - SPEC metadata validation (YAML frontmatter)
608
+ # - EARS structure completeness check
609
+ # - Acceptance criteria quality (Given-When-Then)
610
+ # - @TAG system traceability
611
+ # - Documentation clarity
612
+
613
+ # Expected time: 1-2 minutes
614
+ for i in {1..12}; do
615
+ sleep 10
616
+
617
+ # Check PR review status
618
+ approval=$(gh pr view $pr_num --json reviewDecision --jq '.reviewDecision')
619
+
620
+ if [ "$approval" = "APPROVED" ]; then
621
+ echo "✅ CodeRabbit approved SPEC PR!"
622
+ echo "→ Ready for development with /alfred:2-run SPEC-$spec_id"
623
+ break
624
+ fi
625
+
626
+ echo "⏳ CodeRabbit reviewing... ($i/12)"
627
+ done
628
+ ```
629
+
630
+ **CodeRabbit review includes:**
631
+ - ✅ YAML frontmatter validation (7 required fields)
632
+ - ✅ HISTORY section structure and completeness
633
+ - ✅ EARS requirements clarity (Ubiquitous/Event/State/Optional/Constraints)
634
+ - ✅ Acceptance criteria quality (Given-When-Then scenarios)
635
+ - ✅ @TAG system compliance (SPEC/TEST/CODE/DOC traceability)
636
+ - ✅ Documentation and formatting
637
+
638
+ See `.coderabbit.yaml` for detailed SPEC review checklist.
639
+
552
640
  ## Writing Tips
553
641
 
554
642
  - Information that is not in the product/structure/tech document is supplemented by asking a new question.
@@ -24,7 +24,7 @@ allowed-tools:
24
24
  ---
25
25
 
26
26
  # ⚒️ MoAI-ADK Phase 2: Run the plan - Flexible implementation strategy
27
- > Interactive prompts rely on `Skill("moai-alfred-interactive-questions")` so AskUserQuestion renders TUI selection menus for user surveys and approvals.
27
+ > **Note**: Interactive prompts use `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)` for TUI selection menus. The skill is loaded on-demand when user interaction is required.
28
28
 
29
29
  ## 🎯 Command Purpose
30
30
 
@@ -137,7 +137,7 @@ Task tool call example:
137
137
  3. TAG chain design
138
138
  4. Step-by-step execution plan
139
139
  5. Risks and response plans
140
- 6. Create action plan and use `Skill("moai-alfred-interactive-questions")` to confirm the next action with the user
140
+ 6. Create action plan and use `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)` to confirm the next action with the user
141
141
  (Optional) Explore results: $EXPLORE_RESULTS"
142
142
  ```
143
143
 
@@ -181,26 +181,38 @@ After reviewing the action plan, select one of the following:
181
181
 
182
182
  ## 🚀 STEP 2: Execute task (after user approval)
183
183
 
184
- After user approval (gathered through `Skill("moai-alfred-interactive-questions")`), **call the tdd-implementer agent using the Task tool**.
184
+ After user approval (gathered through `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)`), **call the tdd-implementer agent using the Task tool**.
185
185
 
186
186
  ### ⚙️ How to call an agent
187
187
 
188
188
  **STEP 2 calls tdd-implementer using the Task tool**:
189
189
 
190
190
  ```
191
- Task tool call example:
191
+ Call the Task tool:
192
192
  - subagent_type: "tdd-implementer"
193
- - description: "Execute task"
194
- - prompt: "Please execute the task according to the plan approved in STEP 1.
195
- For TDD scenario:
196
- - Perform RED → GREEN → REFACTOR cycle,
197
- Perform the following for each TAG:
198
- 1. RED Phase: Write a test that fails with the @TEST:ID tag
199
- 2. GREEN Phase: Minimal implementation with the @CODE:ID tag
200
- 3. REFACTOR Phase: Improve code quality
201
- 4. Verify TAG completion conditions and proceed to the next TAG
202
-
203
- Execute on: $ARGUMENTS"
193
+ - description: "Execute task with TDD implementation"
194
+ - prompt: """You are tdd-implementer agent.
195
+
196
+ LANGUAGE CONFIGURATION:
197
+ - conversation_language: {{CONVERSATION_LANGUAGE}}
198
+ - language_name: {{CONVERSATION_LANGUAGE_NAME}}
199
+
200
+ CRITICAL INSTRUCTION:
201
+ Code and technical output MUST be in English.
202
+ Code comments MAY be in {{CONVERSATION_LANGUAGE}} if appropriate.
203
+ Test descriptions and documentation can use {{CONVERSATION_LANGUAGE}}.
204
+
205
+ TASK: Execute the task according to the plan approved in STEP 1.
206
+
207
+ For TDD scenario:
208
+ - Perform RED → GREEN → REFACTOR cycle
209
+ - Perform the following for each TAG:
210
+ 1. RED Phase: Write a test that fails with the @TEST:ID tag
211
+ 2. GREEN Phase: Minimal implementation with the @CODE:ID tag
212
+ 3. REFACTOR Phase: Improve code quality
213
+ 4. Verify TAG completion conditions and proceed to the next TAG
214
+
215
+ Execute on: $ARGUMENTS"""
204
216
  ```
205
217
 
206
218
  ## 🔗 TDD optimization for each language
@@ -254,7 +266,7 @@ The `implementation-planner` agent does the following:
254
266
  2. **Library selection**: Check the latest stable version and verify compatibility through WebFetch
255
267
  3. **TAG chain design**: Determine TAG order and dependency
256
268
  4. **Establishment of implementation strategy**: Step-by-step implementation plan and risk identification
257
- 5. **Create action plan**: Create a structured plan and, via `Skill("moai-alfred-interactive-questions")`, collect user approval before proceeding
269
+ 5. **Create action plan**: Create a structured plan and, via `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)`, collect user approval before proceeding
258
270
 
259
271
  ### Phase 2: Task execution phase (after approval)
260
272
 
@@ -5,30 +5,31 @@ description: "Document synchronization + PR Ready conversion"
5
5
  # - ko: "문서 동기화 + PR Ready 전환"
6
6
  # - ja: "ドキュメント同期 + PR Ready変換"
7
7
  # - zh: "文档同步 + PR Ready转换"
8
- argument-hint: "Mode target path - Mode: auto (default)|force|status|project, target path: Synchronization target path"
8
+ argument-hint: 'Mode target path - Mode: auto (default)|force|status|project, target
9
+ path: Synchronization target path'
9
10
  allowed-tools:
10
- - Read
11
- - Write
12
- - Edit
13
- - MultiEdit
14
- - Bash(git:*)
15
- - Bash(gh:*)
16
- - Bash(python3:*)
17
- - Task
18
- - Grep
19
- - Glob
20
- - TodoWrite
11
+ - Read
12
+ - Write
13
+ - Edit
14
+ - MultiEdit
15
+ - Bash(git:*)
16
+ - Bash(gh:*)
17
+ - Bash(python3:*)
18
+ - Task
19
+ - Grep
20
+ - Glob
21
+ - TodoWrite
21
22
  ---
22
23
 
23
24
  # 📚 MoAI-ADK Step 3: Document Synchronization (+Optional PR Ready)
24
- > Interactive prompts rely on `Skill("moai-alfred-interactive-questions")` so AskUserQuestion renders TUI selection menus for user surveys and approvals.
25
+ > **Note**: Interactive prompts use `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)` for TUI selection menus. The skill is loaded on-demand when user interaction is required.
25
26
 
26
27
  ## 🚀 START HERE
27
28
 
28
29
  **CRITICAL**: Load the TUI Survey Skill FIRST before any user interaction:
29
30
 
30
31
  ```
31
- Skill("moai-alfred-interactive-questions")
32
+ AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)
32
33
  ```
33
34
 
34
35
  This Skill MUST be loaded at the very beginning to enable TUI menu rendering for AskUserQuestion calls throughout this workflow.
@@ -44,7 +45,7 @@ Synchronize code changes to Living Documents and verify @TAG system to ensure co
44
45
  ## 📋 Execution flow
45
46
 
46
47
  **Phase 0: Skill Loading** (IMMEDIATE)
47
- - Load `Skill("moai-alfred-interactive-questions")` at the very start
48
+ - Load `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)` at the very start
48
49
  - This enables TUI menu rendering for all user interactions
49
50
 
50
51
  **Phase 1: Analysis & Planning**
@@ -160,10 +161,26 @@ Invoking the Task tool (Explore agent):
160
161
 
161
162
  2. doc-syncer call (synchronization plan):
162
163
  - subagent_type: "doc-syncer"
163
- - description: "Establish a document synchronization plan"
164
- - prompt: "Please analyze Git changes and establish a document synchronization plan.
165
- $ARGUMENTS
166
- (Optional) TAG validation results: $TAG_VALIDATION_RESULTS"
164
+ - description: "Establish a document synchronization plan"
165
+ - prompt: """You are doc-syncer agent.
166
+
167
+ LANGUAGE CONFIGURATION:
168
+ - conversation_language: {{CONVERSATION_LANGUAGE}}
169
+ - language_name: {{CONVERSATION_LANGUAGE_NAME}}
170
+
171
+ CRITICAL INSTRUCTION:
172
+ Documentation updates MUST respect conversation_language:
173
+ - User-facing documentation (README, guides): {{CONVERSATION_LANGUAGE}}
174
+ - SPEC documents (spec.md, plan.md, acceptance.md): {{CONVERSATION_LANGUAGE}}
175
+ - Code comments: {{CONVERSATION_LANGUAGE}} (when not technical keywords)
176
+ - Technical documentation and YAML frontmatter: English
177
+
178
+ TASK:
179
+ Please analyze Git changes and establish a document synchronization plan.
180
+ Ensure all documentation updates align with the conversation_language setting.
181
+
182
+ $ARGUMENTS
183
+ (Optional) TAG validation results: $TAG_VALIDATION_RESULTS"""
167
184
  ```
168
185
 
169
186
  ### Synchronization analysis in progress
@@ -226,7 +243,7 @@ To skip pre-verification, use the `/alfred:3-sync --skip-pre-check` option.
226
243
 
227
244
  ### User verification steps
228
245
 
229
- After reviewing your sync plan, `Skill("moai-alfred-interactive-questions")` presents the following options for user decision:
246
+ After reviewing your sync plan, `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)` presents the following options for user decision:
230
247
  - **"Proceed"** or **"Start"**: Start synchronization as planned
231
248
  - **"Modify [Contents]"**: Request modifications to your sync plan
232
249
  - **"Abort"**: Abort the sync operation
@@ -235,7 +252,7 @@ After reviewing your sync plan, `Skill("moai-alfred-interactive-questions")` pre
235
252
 
236
253
  ## 🚀 STEP 2: Execute document synchronization (after user approval)
237
254
 
238
- After user approval (collected via `Skill("moai-alfred-interactive-questions")`), the doc-syncer agent performs **Living Document synchronization and @TAG updates**, and optionally executes PR Ready transitions only in team mode.
255
+ After user approval (collected via `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)`), the doc-syncer agent performs **Living Document synchronization and @TAG updates**, and optionally executes PR Ready transitions only in team mode.
239
256
 
240
257
  ### Phase 2 Details: SPEC Completion Processing (Automatic)
241
258
 
@@ -5,11 +5,44 @@ Project information inquiry (language, Git, SPEC progress, etc.)
5
5
  """
6
6
 
7
7
  import json
8
+ import signal
8
9
  import subprocess
10
+ from contextlib import contextmanager
9
11
  from pathlib import Path
10
12
  from typing import Any
11
13
 
12
14
 
15
+ class TimeoutError(Exception):
16
+ """Signal-based timeout exception"""
17
+ pass
18
+
19
+
20
+ @contextmanager
21
+ def timeout_handler(seconds: int):
22
+ """Hard timeout using SIGALRM (works on Unix systems including macOS)
23
+
24
+ This uses kernel-level signal to interrupt ANY blocking operation,
25
+ even if subprocess.run() timeout fails on macOS.
26
+
27
+ Args:
28
+ seconds: Timeout duration in seconds
29
+
30
+ Raises:
31
+ TimeoutError: If operation exceeds timeout
32
+ """
33
+ def _handle_timeout(signum, frame):
34
+ raise TimeoutError(f"Operation timed out after {seconds} seconds")
35
+
36
+ # Set the signal handler
37
+ old_handler = signal.signal(signal.SIGALRM, _handle_timeout)
38
+ signal.alarm(seconds)
39
+ try:
40
+ yield
41
+ finally:
42
+ signal.alarm(0) # Disable alarm
43
+ signal.signal(signal.SIGALRM, old_handler)
44
+
45
+
13
46
  def detect_language(cwd: str) -> str:
14
47
  """Detect project language (supports 20 items languages)
15
48
 
@@ -89,9 +122,10 @@ def detect_language(cwd: str) -> str:
89
122
 
90
123
 
91
124
  def _run_git_command(args: list[str], cwd: str, timeout: int = 2) -> str:
92
- """Git command execution helper function
125
+ """Git command execution with HARD timeout protection
93
126
 
94
127
  Safely execute Git commands and return output.
128
+ Uses SIGALRM (kernel-level interrupt) to handle macOS subprocess timeout bug.
95
129
  Eliminates code duplication and provides consistent error handling.
96
130
 
97
131
  Args:
@@ -103,29 +137,46 @@ def _run_git_command(args: list[str], cwd: str, timeout: int = 2) -> str:
103
137
  Git command output (stdout, removing leading and trailing spaces)
104
138
 
105
139
  Raises:
106
- subprocess.TimeoutExpired: Timeout exceeded
140
+ subprocess.TimeoutExpired: Timeout exceeded (via TimeoutError)
107
141
  subprocess.CalledProcessError: Git command failed
108
142
 
109
143
  Examples:
110
144
  >>> _run_git_command(["branch", "--show-current"], ".")
111
145
  'main'
146
+
147
+ TDD History:
148
+ - RED: Git command hang scenario test
149
+ - GREEN: SIGALRM-based timeout implementation
150
+ - REFACTOR: Exception conversion to subprocess.TimeoutExpired
112
151
  """
113
- result = subprocess.run(
114
- ["git"] + args,
115
- cwd=cwd,
116
- capture_output=True,
117
- text=True,
118
- timeout=timeout,
119
- check=True,
120
- )
121
- return result.stdout.strip()
152
+ try:
153
+ with timeout_handler(timeout):
154
+ result = subprocess.run(
155
+ ["git"] + args,
156
+ cwd=cwd,
157
+ capture_output=True,
158
+ text=True,
159
+ check=False, # Don't raise on non-zero exit - we'll check manually
160
+ )
161
+
162
+ # Check exit code manually
163
+ if result.returncode != 0:
164
+ raise subprocess.CalledProcessError(
165
+ result.returncode, ["git"] + args, result.stdout, result.stderr
166
+ )
167
+
168
+ return result.stdout.strip()
169
+
170
+ except TimeoutError:
171
+ # Convert to subprocess.TimeoutExpired for consistent error handling
172
+ raise subprocess.TimeoutExpired(["git"] + args, timeout)
122
173
 
123
174
 
124
175
  def get_git_info(cwd: str) -> dict[str, Any]:
125
176
  """Gather Git repository information
126
177
 
127
178
  View the current status of a Git repository.
128
- Returns the branch name, commit hash, and number of changes.
179
+ Returns the branch name, commit hash, number of changes, and last commit message.
129
180
  If it is not a Git repository, it returns an empty dictionary.
130
181
 
131
182
  Args:
@@ -136,12 +187,13 @@ def get_git_info(cwd: str) -> dict[str, Any]:
136
187
  - branch: Current branch name (str)
137
188
  - commit: Current commit hash (str, full hash)
138
189
  - changes: Number of changed files (int, staged + unstaged)
190
+ - last_commit: Last commit message (str, subject only)
139
191
 
140
192
  Empty dictionary {} if it is not a Git repository or the query fails.
141
193
 
142
194
  Examples:
143
195
  >>> get_git_info("/path/to/git/repo")
144
- {'branch': 'main', 'commit': 'abc123...', 'changes': 3}
196
+ {'branch': 'main', 'commit': 'abc123...', 'changes': 3, 'last_commit': 'Fix bug'}
145
197
  >>> get_git_info("/path/to/non-git")
146
198
  {}
147
199
 
@@ -149,11 +201,13 @@ def get_git_info(cwd: str) -> dict[str, Any]:
149
201
  - Timeout: 2 seconds for each Git command
150
202
  - Security: Safe execution with subprocess.run(shell=False)
151
203
  - Error handling: Returns an empty dictionary in case of all exceptions
204
+ - Commit message limited to 50 characters for display purposes
152
205
 
153
206
  TDD History:
154
207
  - RED: 3 items scenario test (Git repo, non-Git, error)
155
208
  - GREEN: Implementation of subprocess-based Git command execution
156
209
  - REFACTOR: Add timeout (2 seconds), strengthen exception handling, remove duplicates with helper function
210
+ - UPDATE: Added last_commit message field for SessionStart display
157
211
  """
158
212
  try:
159
213
  # Check if it's a git repository
@@ -165,10 +219,16 @@ def get_git_info(cwd: str) -> dict[str, Any]:
165
219
  status_output = _run_git_command(["status", "--short"], cwd)
166
220
  changes = len([line for line in status_output.splitlines() if line])
167
221
 
222
+ # Get last commit message (subject only, limited to 50 chars)
223
+ last_commit = _run_git_command(["log", "-1", "--format=%s"], cwd)
224
+ if len(last_commit) > 50:
225
+ last_commit = last_commit[:47] + "..."
226
+
168
227
  return {
169
228
  "branch": branch,
170
229
  "commit": commit,
171
230
  "changes": changes,
231
+ "last_commit": last_commit,
172
232
  }
173
233
 
174
234
  except (subprocess.TimeoutExpired, subprocess.CalledProcessError, FileNotFoundError):
@@ -276,9 +336,81 @@ def get_project_language(cwd: str) -> str:
276
336
  return detect_language(cwd)
277
337
 
278
338
 
339
+ def get_package_version_info() -> dict[str, Any]:
340
+ """Check MoAI-ADK current and latest version from PyPI
341
+
342
+ Compares the installed version with the latest version available on PyPI.
343
+ Returns version information for SessionStart hook to display update recommendations.
344
+
345
+ Returns:
346
+ dict with keys:
347
+ - "current": Current installed version
348
+ - "latest": Latest version available on PyPI
349
+ - "update_available": Boolean indicating if update is available
350
+ - "upgrade_command": Recommended upgrade command (if update available)
351
+
352
+ Note:
353
+ - Has 1-second timeout to avoid blocking SessionStart
354
+ - Returns graceful fallback if PyPI check fails
355
+ - Handles version parsing gracefully
356
+ """
357
+ from importlib.metadata import version, PackageNotFoundError
358
+ import urllib.request
359
+ import urllib.error
360
+
361
+ result = {
362
+ "current": "unknown",
363
+ "latest": "unknown",
364
+ "update_available": False,
365
+ "upgrade_command": ""
366
+ }
367
+
368
+ # Get current version
369
+ try:
370
+ result["current"] = version("moai-adk")
371
+ except PackageNotFoundError:
372
+ result["current"] = "dev"
373
+ return result
374
+
375
+ # Get latest version from PyPI (with 1-second timeout)
376
+ try:
377
+ with timeout_handler(1):
378
+ url = "https://pypi.org/pypi/moai-adk/json"
379
+ headers = {"Accept": "application/json"}
380
+ req = urllib.request.Request(url, headers=headers)
381
+ with urllib.request.urlopen(req, timeout=0.8) as response:
382
+ data = json.load(response)
383
+ result["latest"] = data.get("info", {}).get("version", "unknown")
384
+ except (urllib.error.URLError, TimeoutError, Exception):
385
+ # Network error or timeout - return with unknown latest version
386
+ return result
387
+
388
+ # Compare versions (simple comparison)
389
+ if result["current"] != "unknown" and result["latest"] != "unknown":
390
+ try:
391
+ # Parse versions for comparison
392
+ current_parts = [int(x) for x in result["current"].split(".")]
393
+ latest_parts = [int(x) for x in result["latest"].split(".")]
394
+
395
+ # Pad shorter version with zeros
396
+ max_len = max(len(current_parts), len(latest_parts))
397
+ current_parts.extend([0] * (max_len - len(current_parts)))
398
+ latest_parts.extend([0] * (max_len - len(latest_parts)))
399
+
400
+ if latest_parts > current_parts:
401
+ result["update_available"] = True
402
+ result["upgrade_command"] = f"uv pip install --upgrade moai-adk>={result['latest']}"
403
+ except (ValueError, AttributeError):
404
+ # Version parsing failed - skip comparison
405
+ pass
406
+
407
+ return result
408
+
409
+
279
410
  __all__ = [
280
411
  "detect_language",
281
412
  "get_git_info",
282
413
  "count_specs",
283
414
  "get_project_language",
415
+ "get_package_version_info",
284
416
  ]