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.
- moai_adk/core/config/__init__.py +13 -0
- moai_adk/core/config/migration.py +113 -0
- moai_adk/core/project/phase_executor.py +8 -3
- moai_adk/templates/.claude/agents/alfred/cc-manager.md +1 -1
- moai_adk/templates/.claude/agents/alfred/debug-helper.md +2 -2
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +2 -2
- moai_adk/templates/.claude/agents/alfred/git-manager.md +2 -2
- moai_adk/templates/.claude/agents/alfred/implementation-planner.md +2 -2
- moai_adk/templates/.claude/agents/alfred/project-manager.md +6 -6
- moai_adk/templates/.claude/agents/alfred/quality-gate.md +2 -2
- moai_adk/templates/.claude/agents/alfred/skill-factory.md +7 -7
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +2 -2
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +2 -2
- moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +2 -2
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +2 -2
- moai_adk/templates/.claude/commands/alfred/0-project.md +54 -37
- moai_adk/templates/.claude/commands/alfred/1-plan.md +104 -16
- moai_adk/templates/.claude/commands/alfred/2-run.md +28 -16
- moai_adk/templates/.claude/commands/alfred/3-sync.md +38 -21
- moai_adk/templates/.claude/hooks/alfred/core/project.py +145 -13
- moai_adk/templates/.claude/hooks/alfred/handlers/session.py +90 -20
- moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +1 -1
- moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +1 -1
- moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +1 -1
- moai_adk/templates/.moai/config.json +4 -0
- moai_adk/templates/CLAUDE.md +67 -1
- {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/METADATA +1 -1
- {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/RECORD +31 -29
- {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/WHEEL +0 -0
- {moai_adk-0.6.3.dist-info → moai_adk-0.8.0.dist-info}/entry_points.txt +0 -0
- {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
|
|
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: "
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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 `
|
|
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 `
|
|
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
|
-
|
|
177
|
-
|
|
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
|
-
|
|
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
|
|
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 `
|
|
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 `
|
|
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
|
|
191
|
+
Call the Task tool:
|
|
192
192
|
- subagent_type: "tdd-implementer"
|
|
193
|
-
- description: "Execute task"
|
|
194
|
-
- prompt: "
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
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 `
|
|
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:
|
|
8
|
+
argument-hint: 'Mode target path - Mode: auto (default)|force|status|project, target
|
|
9
|
+
path: Synchronization target path'
|
|
9
10
|
allowed-tools:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
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
|
-
|
|
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 `
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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, `
|
|
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 `
|
|
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
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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,
|
|
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
|
]
|