moai-adk 0.7.0__py3-none-any.whl → 0.8.1__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.

Potentially problematic release.


This version of moai-adk might be problematic. Click here for more details.

Files changed (39) hide show
  1. moai_adk/core/issue_creator.py +309 -0
  2. moai_adk/core/project/phase_executor.py +1 -2
  3. moai_adk/core/template_engine.py +253 -0
  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 +27 -4
  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 +9 -9
  17. moai_adk/templates/.claude/commands/alfred/1-plan.md +3 -3
  18. moai_adk/templates/.claude/commands/alfred/2-run.md +4 -4
  19. moai_adk/templates/.claude/commands/alfred/3-sync.md +5 -5
  20. moai_adk/templates/.claude/commands/alfred/9-feedback.md +149 -0
  21. moai_adk/templates/.claude/hooks/alfred/core/project.py +145 -13
  22. moai_adk/templates/.claude/hooks/alfred/handlers/session.py +90 -20
  23. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +1 -1
  24. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +1 -1
  25. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +1 -1
  26. moai_adk/templates/.github/ISSUE_TEMPLATE/spec.yml +5 -3
  27. moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +20 -8
  28. moai_adk/templates/.github/workflows/moai-gitflow.yml +22 -16
  29. moai_adk/templates/.github/workflows/spec-issue-sync.yml +10 -6
  30. moai_adk/templates/.moai/config.json +12 -0
  31. moai_adk/templates/.moai/docs/quick-issue-creation-guide.md +219 -0
  32. moai_adk/templates/.moai/memory/issue-label-mapping.md +150 -0
  33. moai_adk/templates/CLAUDE.md +67 -1
  34. {moai_adk-0.7.0.dist-info → moai_adk-0.8.1.dist-info}/METADATA +123 -1
  35. {moai_adk-0.7.0.dist-info → moai_adk-0.8.1.dist-info}/RECORD +38 -34
  36. moai_adk/templates/.claude/hooks/alfred/test_hook_output.py +0 -175
  37. {moai_adk-0.7.0.dist-info → moai_adk-0.8.1.dist-info}/WHEEL +0 -0
  38. {moai_adk-0.7.0.dist-info → moai_adk-0.8.1.dist-info}/entry_points.txt +0 -0
  39. {moai_adk-0.7.0.dist-info → moai_adk-0.8.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,309 @@
1
+ """
2
+ GitHub Issue Creator for MoAI-ADK quick issue reporting.
3
+
4
+ Enables users to quickly create GitHub Issues with standardized templates
5
+ using `/alfred:9-feedback` interactive dialog.
6
+
7
+ @TAG:ISSUE-CREATOR-001 - GitHub issue creation system
8
+ @TAG:QUICK-REPORTING-001 - Quick issue reporting functionality
9
+ """
10
+
11
+ import subprocess
12
+ from dataclasses import dataclass
13
+ from enum import Enum
14
+ from typing import Any, Dict, List, Optional
15
+
16
+
17
+ class IssueType(Enum):
18
+ """Supported GitHub issue types."""
19
+ BUG = "bug"
20
+ FEATURE = "feature"
21
+ IMPROVEMENT = "improvement"
22
+ QUESTION = "question"
23
+
24
+
25
+ class IssuePriority(Enum):
26
+ """Issue priority levels."""
27
+ CRITICAL = "critical"
28
+ HIGH = "high"
29
+ MEDIUM = "medium"
30
+ LOW = "low"
31
+
32
+
33
+ @dataclass
34
+ class IssueConfig:
35
+ """Configuration for issue creation."""
36
+ issue_type: IssueType
37
+ title: str
38
+ description: str
39
+ priority: IssuePriority = IssuePriority.MEDIUM
40
+ category: Optional[str] = None
41
+ assignees: Optional[List[str]] = None
42
+ custom_labels: Optional[List[str]] = None
43
+
44
+
45
+ class GitHubIssueCreator:
46
+ """
47
+ Creates GitHub Issues using the `gh` CLI.
48
+
49
+ Supports:
50
+ - Multiple issue types (bug, feature, improvement, question)
51
+ - Priority levels and categories
52
+ - Standard templates for each type
53
+ - Label automation
54
+ - Priority emoji indicators
55
+ """
56
+
57
+ # Label mapping for issue types
58
+ LABEL_MAP = {
59
+ IssueType.BUG: ["bug", "reported"],
60
+ IssueType.FEATURE: ["feature-request", "enhancement"],
61
+ IssueType.IMPROVEMENT: ["improvement", "enhancement"],
62
+ IssueType.QUESTION: ["question", "help-wanted"],
63
+ }
64
+
65
+ # Priority emoji
66
+ PRIORITY_EMOJI = {
67
+ IssuePriority.CRITICAL: "🔴",
68
+ IssuePriority.HIGH: "🟠",
69
+ IssuePriority.MEDIUM: "🟡",
70
+ IssuePriority.LOW: "🟢",
71
+ }
72
+
73
+ # Issue type emoji
74
+ TYPE_EMOJI = {
75
+ IssueType.BUG: "🐛",
76
+ IssueType.FEATURE: "✨",
77
+ IssueType.IMPROVEMENT: "⚡",
78
+ IssueType.QUESTION: "❓",
79
+ }
80
+
81
+ def __init__(self, github_token: Optional[str] = None):
82
+ """
83
+ Initialize the GitHub Issue Creator.
84
+
85
+ Args:
86
+ github_token: GitHub API token. If not provided, uses GITHUB_TOKEN env var.
87
+ """
88
+ self.github_token = github_token
89
+ self._check_gh_cli()
90
+
91
+ def _check_gh_cli(self) -> None:
92
+ """
93
+ Check if `gh` CLI is installed and accessible.
94
+
95
+ Raises:
96
+ RuntimeError: If `gh` CLI is not found or not authenticated.
97
+ """
98
+ try:
99
+ result = subprocess.run(
100
+ ["gh", "auth", "status"],
101
+ capture_output=True,
102
+ text=True,
103
+ timeout=5
104
+ )
105
+ if result.returncode != 0:
106
+ raise RuntimeError(
107
+ "GitHub CLI (gh) is not authenticated. "
108
+ "Run `gh auth login` to authenticate."
109
+ )
110
+ except FileNotFoundError:
111
+ raise RuntimeError(
112
+ "GitHub CLI (gh) is not installed. "
113
+ "Please install it: https://cli.github.com"
114
+ )
115
+
116
+ def create_issue(self, config: IssueConfig) -> Dict[str, Any]:
117
+ """
118
+ Create a GitHub issue with the given configuration.
119
+
120
+ Args:
121
+ config: Issue configuration
122
+
123
+ Returns:
124
+ Dictionary containing issue creation result:
125
+ {
126
+ "success": bool,
127
+ "issue_number": int,
128
+ "issue_url": str,
129
+ "message": str
130
+ }
131
+
132
+ Raises:
133
+ RuntimeError: If issue creation fails
134
+ """
135
+ # Build title with emoji and priority
136
+ emoji = self.TYPE_EMOJI.get(config.issue_type, "📋")
137
+ priority_emoji = self.PRIORITY_EMOJI.get(config.priority, "")
138
+ full_title = f"{emoji} [{config.issue_type.value.upper()}] {config.title}"
139
+ if priority_emoji:
140
+ full_title = f"{priority_emoji} {full_title}"
141
+
142
+ # Build body with template
143
+ body = self._build_body(config)
144
+
145
+ # Collect labels
146
+ labels = self.LABEL_MAP.get(config.issue_type, []).copy()
147
+ if config.priority:
148
+ labels.append(f"priority-{config.priority.value}")
149
+ if config.category:
150
+ labels.append(f"category-{config.category.lower().replace(' ', '-')}")
151
+ if config.custom_labels:
152
+ labels.extend(config.custom_labels)
153
+
154
+ # Build gh command
155
+ gh_command = [
156
+ "gh", "issue", "create",
157
+ "--title", full_title,
158
+ "--body", body,
159
+ ]
160
+
161
+ # Add labels
162
+ if labels:
163
+ gh_command.extend(["--label", ",".join(set(labels))])
164
+
165
+ # Add assignees if provided
166
+ if config.assignees:
167
+ gh_command.extend(["--assignee", ",".join(config.assignees)])
168
+
169
+ try:
170
+ result = subprocess.run(
171
+ gh_command,
172
+ capture_output=True,
173
+ text=True,
174
+ timeout=30
175
+ )
176
+
177
+ if result.returncode != 0:
178
+ error_msg = result.stderr or result.stdout
179
+ raise RuntimeError(f"Failed to create GitHub issue: {error_msg}")
180
+
181
+ # Parse issue URL from output
182
+ issue_url = result.stdout.strip()
183
+ issue_number = self._extract_issue_number(issue_url)
184
+
185
+ return {
186
+ "success": True,
187
+ "issue_number": issue_number,
188
+ "issue_url": issue_url,
189
+ "message": f"✅ GitHub Issue #{issue_number} created successfully",
190
+ "title": full_title,
191
+ "labels": labels,
192
+ }
193
+
194
+ except subprocess.TimeoutExpired:
195
+ raise RuntimeError("GitHub issue creation timed out")
196
+ except Exception as e:
197
+ raise RuntimeError(f"Error creating GitHub issue: {e}")
198
+
199
+ def _build_body(self, config: IssueConfig) -> str:
200
+ """
201
+ Build the issue body based on issue type.
202
+
203
+ Args:
204
+ config: Issue configuration
205
+
206
+ Returns:
207
+ Formatted issue body
208
+ """
209
+ body = config.description
210
+
211
+ # Add metadata footer
212
+ footer = "\n\n---\n\n"
213
+ footer += f"**Type**: {config.issue_type.value} \n"
214
+ footer += f"**Priority**: {config.priority.value} \n"
215
+ if config.category:
216
+ footer += f"**Category**: {config.category} \n"
217
+ footer += f"**Created via**: `/alfred:9-feedback`"
218
+
219
+ return body + footer
220
+
221
+ @staticmethod
222
+ def _extract_issue_number(url: str) -> int:
223
+ """
224
+ Extract issue number from GitHub URL.
225
+
226
+ Args:
227
+ url: GitHub issue URL
228
+
229
+ Returns:
230
+ Issue number
231
+
232
+ Raises:
233
+ ValueError: If unable to extract issue number
234
+ """
235
+ try:
236
+ # URL format: https://github.com/owner/repo/issues/123
237
+ return int(url.strip().split("/")[-1])
238
+ except (ValueError, IndexError):
239
+ raise ValueError(f"Unable to extract issue number from URL: {url}")
240
+
241
+ def format_result(self, result: Dict[str, Any]) -> str:
242
+ """
243
+ Format the issue creation result for display.
244
+
245
+ Args:
246
+ result: Issue creation result
247
+
248
+ Returns:
249
+ Formatted result string
250
+ """
251
+ if result["success"]:
252
+ output = f"{result['message']}\n"
253
+ output += f"📋 Title: {result['title']}\n"
254
+ output += f"🔗 URL: {result['issue_url']}\n"
255
+ if result.get("labels"):
256
+ output += f"🏷️ Labels: {', '.join(result['labels'])}\n"
257
+ return output
258
+ else:
259
+ return f"❌ Failed to create issue: {result.get('message', 'Unknown error')}"
260
+
261
+
262
+ class IssueCreatorFactory:
263
+ """
264
+ Factory for creating issue creators with predefined configurations.
265
+ """
266
+
267
+ @staticmethod
268
+ def create_bug_issue(title: str, description: str, priority: IssuePriority = IssuePriority.HIGH) -> IssueConfig:
269
+ """Create a bug report issue configuration."""
270
+ return IssueConfig(
271
+ issue_type=IssueType.BUG,
272
+ title=title,
273
+ description=description,
274
+ priority=priority,
275
+ category="Bug Report",
276
+ )
277
+
278
+ @staticmethod
279
+ def create_feature_issue(title: str, description: str, priority: IssuePriority = IssuePriority.MEDIUM) -> IssueConfig:
280
+ """Create a feature request issue configuration."""
281
+ return IssueConfig(
282
+ issue_type=IssueType.FEATURE,
283
+ title=title,
284
+ description=description,
285
+ priority=priority,
286
+ category="Feature Request",
287
+ )
288
+
289
+ @staticmethod
290
+ def create_improvement_issue(title: str, description: str, priority: IssuePriority = IssuePriority.MEDIUM) -> IssueConfig:
291
+ """Create an improvement issue configuration."""
292
+ return IssueConfig(
293
+ issue_type=IssueType.IMPROVEMENT,
294
+ title=title,
295
+ description=description,
296
+ priority=priority,
297
+ category="Improvement",
298
+ )
299
+
300
+ @staticmethod
301
+ def create_question_issue(title: str, description: str, priority: IssuePriority = IssuePriority.LOW) -> IssueConfig:
302
+ """Create a question/discussion issue configuration."""
303
+ return IssueConfig(
304
+ issue_type=IssueType.QUESTION,
305
+ title=title,
306
+ description=description,
307
+ priority=priority,
308
+ category="Question",
309
+ )
@@ -26,6 +26,7 @@ from moai_adk.core.project.backup_utils import (
26
26
  is_protected_path,
27
27
  )
28
28
  from moai_adk.core.project.validator import ProjectValidator
29
+ from moai_adk.core.template.processor import TemplateProcessor
29
30
 
30
31
  console = Console()
31
32
 
@@ -136,8 +137,6 @@ class PhaseExecutor:
136
137
  )
137
138
 
138
139
  # Copy resources via TemplateProcessor in silent mode
139
- from moai_adk.core.template import TemplateProcessor
140
-
141
140
  processor = TemplateProcessor(project_path)
142
141
 
143
142
  # Set template variable context (if provided)
@@ -0,0 +1,253 @@
1
+ """
2
+ Template engine for parameterizing GitHub templates and other configuration files.
3
+
4
+ Supports Jinja2-style templating with variable substitution and conditional sections.
5
+ Enables users to customize MoAI-ADK templates for their own projects.
6
+
7
+ @TAG:TEMPLATE-ENGINE-001 - Template variable substitution system
8
+ @TAG:GITHUB-CUSTOMIZATION-001 - GitHub template parameterization
9
+ """
10
+
11
+ from pathlib import Path
12
+ from typing import Any, Dict, Optional
13
+
14
+ from jinja2 import (
15
+ Environment,
16
+ FileSystemLoader,
17
+ StrictUndefined,
18
+ TemplateNotFound,
19
+ TemplateRuntimeError,
20
+ TemplateSyntaxError,
21
+ )
22
+
23
+
24
+ class TemplateEngine:
25
+ """
26
+ Jinja2-based template engine for MoAI-ADK configuration and GitHub templates.
27
+
28
+ Supports:
29
+ - Variable substitution: {{PROJECT_NAME}}, {{SPEC_DIR}}, etc.
30
+ - Conditional sections: {{#ENABLE_TRUST_5}}...{{/ENABLE_TRUST_5}}
31
+ - File-based and string-based template rendering
32
+ """
33
+
34
+ def __init__(self, strict_undefined: bool = False):
35
+ """
36
+ Initialize the template engine.
37
+
38
+ Args:
39
+ strict_undefined: If True, raise error on undefined variables.
40
+ If False, render undefined variables as empty strings.
41
+ """
42
+ self.strict_undefined = strict_undefined
43
+ self.undefined_behavior = StrictUndefined if strict_undefined else None
44
+
45
+ def render_string(
46
+ self,
47
+ template_string: str,
48
+ variables: Dict[str, Any]
49
+ ) -> str:
50
+ """
51
+ Render a Jinja2 template string with provided variables.
52
+
53
+ Args:
54
+ template_string: The template content as a string
55
+ variables: Dictionary of variables to substitute
56
+
57
+ Returns:
58
+ Rendered template string
59
+
60
+ Raises:
61
+ TemplateSyntaxError: If template syntax is invalid
62
+ TemplateRuntimeError: If variable substitution fails in strict mode
63
+ """
64
+ try:
65
+ env = Environment(
66
+ undefined=self.undefined_behavior,
67
+ trim_blocks=False,
68
+ lstrip_blocks=False
69
+ )
70
+ template = env.from_string(template_string)
71
+ return template.render(**variables)
72
+ except (TemplateSyntaxError, TemplateRuntimeError) as e:
73
+ raise RuntimeError(f"Template rendering error: {e}")
74
+
75
+ def render_file(
76
+ self,
77
+ template_path: Path,
78
+ variables: Dict[str, Any],
79
+ output_path: Optional[Path] = None
80
+ ) -> str:
81
+ """
82
+ Render a Jinja2 template file with provided variables.
83
+
84
+ Args:
85
+ template_path: Path to the template file
86
+ variables: Dictionary of variables to substitute
87
+ output_path: If provided, write rendered content to this path
88
+
89
+ Returns:
90
+ Rendered template content
91
+
92
+ Raises:
93
+ FileNotFoundError: If template file doesn't exist
94
+ TemplateSyntaxError: If template syntax is invalid
95
+ TemplateRuntimeError: If variable substitution fails in strict mode
96
+ """
97
+ if not template_path.exists():
98
+ raise FileNotFoundError(f"Template file not found: {template_path}")
99
+
100
+ template_dir = template_path.parent
101
+ template_name = template_path.name
102
+
103
+ try:
104
+ env = Environment(
105
+ loader=FileSystemLoader(str(template_dir)),
106
+ undefined=self.undefined_behavior,
107
+ trim_blocks=False,
108
+ lstrip_blocks=False
109
+ )
110
+ template = env.get_template(template_name)
111
+ rendered = template.render(**variables)
112
+
113
+ if output_path:
114
+ output_path.parent.mkdir(parents=True, exist_ok=True)
115
+ output_path.write_text(rendered, encoding='utf-8')
116
+
117
+ return rendered
118
+ except TemplateNotFound:
119
+ raise FileNotFoundError(f"Template not found in {template_dir}: {template_name}")
120
+ except (TemplateSyntaxError, TemplateRuntimeError) as e:
121
+ raise RuntimeError(f"Template rendering error in {template_path}: {e}")
122
+
123
+ def render_directory(
124
+ self,
125
+ template_dir: Path,
126
+ output_dir: Path,
127
+ variables: Dict[str, Any],
128
+ pattern: str = "**/*.{md,yml,yaml,json}"
129
+ ) -> Dict[str, str]:
130
+ """
131
+ Render all template files in a directory.
132
+
133
+ Args:
134
+ template_dir: Source directory containing templates
135
+ output_dir: Destination directory for rendered files
136
+ variables: Dictionary of variables to substitute
137
+ pattern: Glob pattern for files to process (default: template files)
138
+
139
+ Returns:
140
+ Dictionary mapping input paths to rendered content
141
+
142
+ Raises:
143
+ FileNotFoundError: If template directory doesn't exist
144
+ """
145
+ if not template_dir.exists():
146
+ raise FileNotFoundError(f"Template directory not found: {template_dir}")
147
+
148
+ results = {}
149
+ output_dir.mkdir(parents=True, exist_ok=True)
150
+
151
+ for template_file in template_dir.glob(pattern):
152
+ if template_file.is_file():
153
+ relative_path = template_file.relative_to(template_dir)
154
+ output_file = output_dir / relative_path
155
+
156
+ try:
157
+ rendered = self.render_file(template_file, variables, output_file)
158
+ results[str(relative_path)] = rendered
159
+ except Exception as e:
160
+ raise RuntimeError(f"Error rendering {relative_path}: {e}")
161
+
162
+ return results
163
+
164
+ @staticmethod
165
+ def get_default_variables(config: Dict[str, Any]) -> Dict[str, Any]:
166
+ """
167
+ Extract template variables from project configuration.
168
+
169
+ Args:
170
+ config: Project configuration dictionary (from .moai/config.json)
171
+
172
+ Returns:
173
+ Dictionary of template variables
174
+ """
175
+ github_config = config.get("github", {}).get("templates", {})
176
+ project_config = config.get("project", {})
177
+
178
+ return {
179
+ # Project information
180
+ "PROJECT_NAME": project_config.get("name", "MyProject"),
181
+ "PROJECT_DESCRIPTION": project_config.get("description", ""),
182
+ "PROJECT_MODE": project_config.get("mode", "team"), # team or personal
183
+
184
+ # Directory structure
185
+ "SPEC_DIR": github_config.get("spec_directory", ".moai/specs"),
186
+ "DOCS_DIR": github_config.get("docs_directory", ".moai/docs"),
187
+ "TEST_DIR": github_config.get("test_directory", "tests"),
188
+
189
+ # Feature flags
190
+ "ENABLE_TRUST_5": github_config.get("enable_trust_5", True),
191
+ "ENABLE_TAG_SYSTEM": github_config.get("enable_tag_system", True),
192
+ "ENABLE_ALFRED_COMMANDS": github_config.get("enable_alfred_commands", True),
193
+
194
+ # Language configuration
195
+ "CONVERSATION_LANGUAGE": project_config.get("conversation_language", "en"),
196
+ "CONVERSATION_LANGUAGE_NAME": project_config.get("conversation_language_name", "English"),
197
+
198
+ # Additional metadata
199
+ "MOAI_VERSION": config.get("moai", {}).get("version", "0.7.0"),
200
+ }
201
+
202
+
203
+ class TemplateVariableValidator:
204
+ """
205
+ Validates template variables for completeness and correctness.
206
+ Ensures all required variables are present before rendering.
207
+ """
208
+
209
+ REQUIRED_VARIABLES = {
210
+ "PROJECT_NAME": str,
211
+ "SPEC_DIR": str,
212
+ "DOCS_DIR": str,
213
+ "TEST_DIR": str,
214
+ }
215
+
216
+ OPTIONAL_VARIABLES = {
217
+ "PROJECT_DESCRIPTION": (str, type(None)),
218
+ "PROJECT_MODE": str,
219
+ "ENABLE_TRUST_5": bool,
220
+ "ENABLE_TAG_SYSTEM": bool,
221
+ "ENABLE_ALFRED_COMMANDS": bool,
222
+ "CONVERSATION_LANGUAGE": str,
223
+ "CONVERSATION_LANGUAGE_NAME": str,
224
+ }
225
+
226
+ @classmethod
227
+ def validate(cls, variables: Dict[str, Any]) -> tuple[bool, list[str]]:
228
+ """
229
+ Validate template variables.
230
+
231
+ Args:
232
+ variables: Dictionary of variables to validate
233
+
234
+ Returns:
235
+ Tuple of (is_valid, list_of_errors)
236
+ """
237
+ errors = []
238
+
239
+ # Check required variables
240
+ for var_name, var_type in cls.REQUIRED_VARIABLES.items():
241
+ if var_name not in variables:
242
+ errors.append(f"Missing required variable: {var_name}")
243
+ elif not isinstance(variables[var_name], var_type):
244
+ errors.append(f"Invalid type for {var_name}: expected {var_type.__name__}, got {type(variables[var_name]).__name__}")
245
+
246
+ # Check optional variables (if present)
247
+ for var_name, var_type in cls.OPTIONAL_VARIABLES.items():
248
+ if var_name in variables:
249
+ if not isinstance(variables[var_name], var_type):
250
+ type_names = " or ".join(t.__name__ for t in var_type) if isinstance(var_type, tuple) else var_type.__name__
251
+ errors.append(f"Invalid type for {var_name}: expected {type_names}, got {type(variables[var_name]).__name__}")
252
+
253
+ return len(errors) == 0, errors
@@ -54,7 +54,7 @@ Alfred translates Claude Code configuration requirements to English before invok
54
54
  - `Skill("moai-alfred-git-workflow")` - Git strategy impact
55
55
  - Domain skills (CLI/Data Science/Database/etc) - When relevant
56
56
  - Language skills (23 available) - Based on detected language
57
- - `Skill("moai-alfred-interactive-questions")` - User clarification
57
+ - `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)` - User clarification
58
58
 
59
59
  ---
60
60
 
@@ -6,7 +6,7 @@ model: sonnet
6
6
  ---
7
7
 
8
8
  # Debug Helper - Integrated debugging expert
9
- > **Note**: Interactive prompts use `Skill("moai-alfred-interactive-questions")` for TUI selection menus. The skill is loaded on-demand when user interaction is required.
9
+ > **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.
10
10
 
11
11
  You are the integrated debugging expert responsible for **all errors**.
12
12
 
@@ -45,7 +45,7 @@ Alfred translates error reports and debugging requirements to English before inv
45
45
  - `Skill("moai-essentials-review")`: Loaded when structural problems or solutions to prevent recurrence need to be presented.
46
46
  - Language-specific skills: Based on the result of `Skill("moai-alfred-language-detection")`, select only the one relevant language skill (e.g., `Skill("moai-lang-python")`, `Skill("moai-lang-typescript")`, etc.).
47
47
  - `Skill("moai-alfred-tag-scanning")`: Called when missing/mismatching TAG is suspected.
48
- - `Skill("moai-alfred-interactive-questions")`: Executed when user selection among multiple solutions is required.
48
+ - `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)`: Executed when user selection among multiple solutions is required.
49
49
 
50
50
  ### Expert Traits
51
51
 
@@ -6,7 +6,7 @@ model: haiku
6
6
  ---
7
7
 
8
8
  # Doc Syncer - Document Management/Synchronization Expert
9
- > **Note**: Interactive prompts use `Skill("moai-alfred-interactive-questions")` for TUI selection menus. The skill is loaded on-demand when user interaction is required.
9
+ > **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.
10
10
 
11
11
  All Git tasks are handled by the git-manager agent, including managing PRs, committing, and assigning reviewers. doc-syncer is only responsible for document synchronization.
12
12
 
@@ -47,7 +47,7 @@ Alfred translates document synchronization requirements to English before invoki
47
47
  - `Skill("moai-foundation-specs")`: Use only when SPEC metadata has changed or document consistency verification is required.
48
48
  - `Skill("moai-alfred-git-workflow")`: Called when performing a PR Ready transition or Git cleanup in team mode.
49
49
  - `Skill("moai-alfred-code-reviewer")`: Load when you need to review the quality of a code snippet to be included in a document.
50
- - `Skill("moai-alfred-interactive-questions")`: Executed when checking with the user whether to approve/skip the synchronization range.
50
+ - `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)`: Executed when checking with the user whether to approve/skip the synchronization range.
51
51
 
52
52
  ### Expert Traits
53
53
 
@@ -6,7 +6,7 @@ model: haiku
6
6
  ---
7
7
 
8
8
  # Git Manager - Agent dedicated to Git tasks
9
- > **Note**: Interactive prompts use `Skill("moai-alfred-interactive-questions")` for TUI selection menus. The skill is loaded on-demand when user interaction is required.
9
+ > **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.
10
10
 
11
11
  This is a dedicated agent that optimizes and processes all Git operations in MoAI-ADK for each mode.
12
12
 
@@ -45,7 +45,7 @@ This ensures git history is always in English for global team compatibility.
45
45
  - `Skill("moai-foundation-git")`: Called when this is a new repository or the Git standard needs to be redefined.
46
46
  - `Skill("moai-alfred-trust-validation")`: Load when TRUST gate needs to be passed before commit/PR.
47
47
  - `Skill("moai-alfred-tag-scanning")`: Use only when TAG connection is required in the commit message.
48
- - `Skill("moai-alfred-interactive-questions")`: Called when user approval is obtained before performing risky operations such as rebase/force push.
48
+ - `AskUserQuestion tool (documented in moai-alfred-interactive-questions skill)`: Called when user approval is obtained before performing risky operations such as rebase/force push.
49
49
 
50
50
  ### Expert Traits
51
51
 
@@ -358,9 +358,10 @@ Git-manager automatically handles the following exception situations:
358
358
  **All commits created by git-manager follow this signature format**:
359
359
 
360
360
  ```
361
- 🤖 Generated with [Claude Code](https://claude.com/claude-code)
361
+ 🎩 Alfred@MoAI
362
+ 🔗 https://adk.mo.ai.kr
362
363
 
363
- Co-Authored-By: 🎩 Alfred@[MoAI](https://adk.mo.ai.kr)
364
+ Co-Authored-By: Claude <noreply@anthropic.com>
364
365
  ```
365
366
 
366
367
  This signature applies to all Git operations:
@@ -370,6 +371,28 @@ This signature applies to all Git operations:
370
371
  - Merge commits
371
372
  - Tag creation
372
373
 
374
+ **Signature breakdown**:
375
+ - `🎩 Alfred@MoAI` - Alfred 에이전트의 공식 식별자
376
+ - `🔗 https://adk.mo.ai.kr` - MoAI-ADK 공식 홈페이지 링크
377
+ - `Co-Authored-By: Claude <noreply@anthropic.com>` - Claude AI 협력자 표시
378
+
379
+ **Implementation Example (HEREDOC)**:
380
+ ```bash
381
+ git commit -m "$(cat <<'EOF'
382
+ feat(update): Implement 3-stage workflow with config version comparison
383
+
384
+ - Stage 2: Config version comparison (NEW)
385
+ - 70-80% performance improvement
386
+ - All tests passing
387
+
388
+ 🎩 Alfred@MoAI
389
+ 🔗 https://adk.mo.ai.kr
390
+
391
+ Co-Authored-By: Claude <noreply@anthropic.com>
392
+ EOF
393
+ )"
394
+ ```
395
+
373
396
  ---
374
397
 
375
398
  **git-manager provides a simple and stable work environment with direct Git commands instead of complex scripts.**