codpilot-cli 0.1.0__tar.gz
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.
- codpilot_cli-0.1.0/.claude/settings.local.json +10 -0
- codpilot_cli-0.1.0/.gitignore +12 -0
- codpilot_cli-0.1.0/.python-version +1 -0
- codpilot_cli-0.1.0/PKG-INFO +88 -0
- codpilot_cli-0.1.0/README.md +67 -0
- codpilot_cli-0.1.0/app/agents/feature_agent.py +49 -0
- codpilot_cli-0.1.0/app/agents/pr_review_agent.py +70 -0
- codpilot_cli-0.1.0/app/agents/suggestion_agent.py +59 -0
- codpilot_cli-0.1.0/app/agents/tools/github_mcp.py +23 -0
- codpilot_cli-0.1.0/app/cli/commands/run.py +44 -0
- codpilot_cli-0.1.0/app/cli/commands/version.py +8 -0
- codpilot_cli-0.1.0/app/cli/inputs.py +164 -0
- codpilot_cli-0.1.0/app/cli/llm.py +100 -0
- codpilot_cli-0.1.0/app/cli/main.py +31 -0
- codpilot_cli-0.1.0/app/cli/spinner.py +11 -0
- codpilot_cli-0.1.0/app/services/build_model_service.py +14 -0
- codpilot_cli-0.1.0/app/services/runner_service.py +34 -0
- codpilot_cli-0.1.0/app/workflows/agent_workflow.py +50 -0
- codpilot_cli-0.1.0/pyproject.toml +34 -0
- codpilot_cli-0.1.0/uv.lock +2515 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.14
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: codpilot-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A multi-agent CLI tool that integrates with GitHub to review PRs, create features, and suggest changes.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Keywords: cli,codpilot,github
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
12
|
+
Requires-Python: >=3.14
|
|
13
|
+
Requires-Dist: google-adk>=1.24.0
|
|
14
|
+
Requires-Dist: keyring>=25.7.0
|
|
15
|
+
Requires-Dist: litellm>=1.81.11
|
|
16
|
+
Requires-Dist: python-dotenv>=1.2.1
|
|
17
|
+
Requires-Dist: questionary>=2.1.1
|
|
18
|
+
Requires-Dist: rich>=14.3.2
|
|
19
|
+
Requires-Dist: typer>=0.23.1
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
|
|
22
|
+
# CodePilot CLI
|
|
23
|
+
|
|
24
|
+
A multi agent CLI tool that integrates with GitHub that can help you to review pull requests, create new features, and suggest changes on your behalf — all from your terminal.
|
|
25
|
+
|
|
26
|
+
## Features
|
|
27
|
+
|
|
28
|
+
**Review PR** — Analyzes the pull request and posts inline comments with suggestions.
|
|
29
|
+
|
|
30
|
+
**Create Feature** — It can implements new features, then opens a draft pull request against the target repository.
|
|
31
|
+
|
|
32
|
+
**Suggest Changes** — Participate in GitHub Issue discussions, analyze the codebase and conversation, and post technical suggestions as comments.
|
|
33
|
+
|
|
34
|
+
## Available Commands
|
|
35
|
+
|
|
36
|
+
| Command | Description |
|
|
37
|
+
| ------------------------------ | ----------------------------- |
|
|
38
|
+
| `codepilot run` | Run the agent |
|
|
39
|
+
| `codepilot reset-github-token` | Reset the stored GitHub token |
|
|
40
|
+
| `codepilot change-llm` | Change the LLM model |
|
|
41
|
+
| `codepilot --version, -v` | Show the current version |
|
|
42
|
+
|
|
43
|
+
`codepilot run` has the following options:
|
|
44
|
+
|
|
45
|
+
- Review PR
|
|
46
|
+
- Create Feature
|
|
47
|
+
- Suggest Changes
|
|
48
|
+
|
|
49
|
+
## Prerequisites
|
|
50
|
+
|
|
51
|
+
- Python 3.14+
|
|
52
|
+
- A GitHub personal access token
|
|
53
|
+
- An API key for at least one LLM provider (Gemini, OpenAI, or Anthropic)
|
|
54
|
+
|
|
55
|
+
## Installing locally
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/<your-username>/ai-coding-agent.git
|
|
59
|
+
cd codepilot
|
|
60
|
+
pip install -e .
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Verify the installation:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
codepilot --version
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Usage
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
codepilot run
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The interactive prompt will walk you through:
|
|
76
|
+
|
|
77
|
+
1. Selecting an agent (Review PR / Create Feature / Suggest Changes)
|
|
78
|
+
2. Entering the GitHub URL (PR, repository, or issue depending on the agent)
|
|
79
|
+
3. Choosing an LLM provider (Gemini / OpenAI / Anthropic)
|
|
80
|
+
4. Providing API credentials for github and LLM (cached in your system keychain for future runs)
|
|
81
|
+
|
|
82
|
+
## Supported Models
|
|
83
|
+
|
|
84
|
+
| Provider | Model |
|
|
85
|
+
| --------- | ---------------------------- |
|
|
86
|
+
| Gemini | `gemini-3-flash-preview` |
|
|
87
|
+
| OpenAI | `gpt-5-mini` |
|
|
88
|
+
| Anthropic | `claude-3-7-sonnet-20250219` |
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# CodePilot CLI
|
|
2
|
+
|
|
3
|
+
A multi agent CLI tool that integrates with GitHub that can help you to review pull requests, create new features, and suggest changes on your behalf — all from your terminal.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
**Review PR** — Analyzes the pull request and posts inline comments with suggestions.
|
|
8
|
+
|
|
9
|
+
**Create Feature** — It can implements new features, then opens a draft pull request against the target repository.
|
|
10
|
+
|
|
11
|
+
**Suggest Changes** — Participate in GitHub Issue discussions, analyze the codebase and conversation, and post technical suggestions as comments.
|
|
12
|
+
|
|
13
|
+
## Available Commands
|
|
14
|
+
|
|
15
|
+
| Command | Description |
|
|
16
|
+
| ------------------------------ | ----------------------------- |
|
|
17
|
+
| `codepilot run` | Run the agent |
|
|
18
|
+
| `codepilot reset-github-token` | Reset the stored GitHub token |
|
|
19
|
+
| `codepilot change-llm` | Change the LLM model |
|
|
20
|
+
| `codepilot --version, -v` | Show the current version |
|
|
21
|
+
|
|
22
|
+
`codepilot run` has the following options:
|
|
23
|
+
|
|
24
|
+
- Review PR
|
|
25
|
+
- Create Feature
|
|
26
|
+
- Suggest Changes
|
|
27
|
+
|
|
28
|
+
## Prerequisites
|
|
29
|
+
|
|
30
|
+
- Python 3.14+
|
|
31
|
+
- A GitHub personal access token
|
|
32
|
+
- An API key for at least one LLM provider (Gemini, OpenAI, or Anthropic)
|
|
33
|
+
|
|
34
|
+
## Installing locally
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/<your-username>/ai-coding-agent.git
|
|
38
|
+
cd codepilot
|
|
39
|
+
pip install -e .
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Verify the installation:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
codepilot --version
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
codepilot run
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The interactive prompt will walk you through:
|
|
55
|
+
|
|
56
|
+
1. Selecting an agent (Review PR / Create Feature / Suggest Changes)
|
|
57
|
+
2. Entering the GitHub URL (PR, repository, or issue depending on the agent)
|
|
58
|
+
3. Choosing an LLM provider (Gemini / OpenAI / Anthropic)
|
|
59
|
+
4. Providing API credentials for github and LLM (cached in your system keychain for future runs)
|
|
60
|
+
|
|
61
|
+
## Supported Models
|
|
62
|
+
|
|
63
|
+
| Provider | Model |
|
|
64
|
+
| --------- | ---------------------------- |
|
|
65
|
+
| Gemini | `gemini-3-flash-preview` |
|
|
66
|
+
| OpenAI | `gpt-5-mini` |
|
|
67
|
+
| Anthropic | `claude-3-7-sonnet-20250219` |
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from google.adk.agents.llm_agent import LlmAgent
|
|
2
|
+
from google.adk.agents.loop_agent import LoopAgent
|
|
3
|
+
from google.adk.tools.tool_context import ToolContext
|
|
4
|
+
from app.agents.tools.github_mcp import github_mcp
|
|
5
|
+
from app.services.build_model_service import build_model
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def finish_task(tool_context: ToolContext):
|
|
9
|
+
"""Call this ONLY when a Pull Request URL has been successfully generated."""
|
|
10
|
+
tool_context.actions.escalate = True
|
|
11
|
+
return {"status": "complete"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
base_feature_agent = LlmAgent(
|
|
15
|
+
name="CodeAnalyzerAgent",
|
|
16
|
+
model=build_model(),
|
|
17
|
+
instruction="""
|
|
18
|
+
You are a coding agent.
|
|
19
|
+
1. Analyze the repo. 2. Make changes. 3. Raise a Draft Pull Request.
|
|
20
|
+
|
|
21
|
+
IMPORTANT: If the chat history shows you already modified files but missed the PR,
|
|
22
|
+
skip the analysis and call the PR tool immediately.
|
|
23
|
+
""",
|
|
24
|
+
output_key="worker_output",
|
|
25
|
+
tools=[github_mcp()],
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
verifier_agent = LlmAgent(
|
|
29
|
+
name="CodeVerifierAgent",
|
|
30
|
+
model=build_model(),
|
|
31
|
+
instruction="""
|
|
32
|
+
Review the following output from the CodeAnalyzer:
|
|
33
|
+
|
|
34
|
+
\"\"\"
|
|
35
|
+
{{worker_output}}
|
|
36
|
+
\"\"\"
|
|
37
|
+
|
|
38
|
+
Task:
|
|
39
|
+
- If a GitHub Pull Request URL is visible above, call 'finish_task' immediately.
|
|
40
|
+
- If NO Pull Request URL is found, explicitly tell the worker: 'You failed to create a PR. Please execute the PR tool now.'
|
|
41
|
+
""",
|
|
42
|
+
tools=[finish_task],
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
feature_agent = LoopAgent(
|
|
46
|
+
name="PrGenerationAgent",
|
|
47
|
+
sub_agents=[base_feature_agent, verifier_agent],
|
|
48
|
+
max_iterations=3,
|
|
49
|
+
)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from google.adk.agents.llm_agent import LlmAgent
|
|
2
|
+
from app.agents.tools.github_mcp import github_mcp
|
|
3
|
+
from app.services.build_model_service import build_model
|
|
4
|
+
from google.adk.tools.tool_context import ToolContext
|
|
5
|
+
from google.adk.agents.loop_agent import LoopAgent
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def finish_review(tool_context: ToolContext):
|
|
9
|
+
"""Call this ONLY when the final PR summary and recommendation (Approve/Request Changes) have been posted."""
|
|
10
|
+
tool_context.actions.escalate = True
|
|
11
|
+
return {"status": "review_submitted"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
base_review_agent = LlmAgent(
|
|
15
|
+
name="PullRequestReviewWorker",
|
|
16
|
+
model=build_model(),
|
|
17
|
+
instruction="""
|
|
18
|
+
You are a senior software engineer.
|
|
19
|
+
|
|
20
|
+
TASK:
|
|
21
|
+
1. Use github_mcp to get the PR diff.
|
|
22
|
+
2. Review files one by one.
|
|
23
|
+
3. Identify issues in:
|
|
24
|
+
- Correctness
|
|
25
|
+
- Edge cases
|
|
26
|
+
- Security
|
|
27
|
+
- Performance
|
|
28
|
+
- Readability & maintainability
|
|
29
|
+
- Architecture & consistency
|
|
30
|
+
- Tests (missing or insufficient)
|
|
31
|
+
4. For each issue, use the 'post_inline_comment' tool.
|
|
32
|
+
|
|
33
|
+
RULES
|
|
34
|
+
- NO POSITIVE FEEDBACK: Never post "Good," "Consistent," or "Correct." If code is good, skip it.
|
|
35
|
+
- NO CHATTER: Do not explain your process.
|
|
36
|
+
- For code improvement comment must include a ```suggestion``` block.
|
|
37
|
+
|
|
38
|
+
IMPORTANT: Check the chat history. If you have already commented on certain files,
|
|
39
|
+
DO NOT repeat them. Move to the next file in the diff.
|
|
40
|
+
|
|
41
|
+
When finished with ALL files, provide a 'Final Summary' and call the tool to submit the overall review.
|
|
42
|
+
""",
|
|
43
|
+
output_key="review_output",
|
|
44
|
+
tools=[github_mcp()],
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
review_verifier_agent = LlmAgent(
|
|
48
|
+
name="ReviewVerifierAgent",
|
|
49
|
+
model=build_model(),
|
|
50
|
+
instruction="""
|
|
51
|
+
You are an auditor. Examine the 'review_output' provided below:
|
|
52
|
+
|
|
53
|
+
REVIEW_LOG:
|
|
54
|
+
{{review_output}}
|
|
55
|
+
|
|
56
|
+
CHECKLIST:
|
|
57
|
+
- Did the worker post a final summary? (Yes/No)
|
|
58
|
+
- Did the worker submit a formal recommendation (Approve/Reject)? (Yes/No)
|
|
59
|
+
|
|
60
|
+
IF BOTH ARE YES: Call 'finish_review' immediately.
|
|
61
|
+
IF NO: Tell the worker exactly what is missing (e.g., 'You reviewed the files but forgot to submit the final Approval').
|
|
62
|
+
""",
|
|
63
|
+
tools=[finish_review],
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
pr_review_agent = LoopAgent(
|
|
67
|
+
name="AutonomousPrReviewer",
|
|
68
|
+
sub_agents=[base_review_agent, review_verifier_agent],
|
|
69
|
+
max_iterations=5,
|
|
70
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from google.adk.agents.llm_agent import LlmAgent
|
|
2
|
+
from google.adk.agents.loop_agent import LoopAgent
|
|
3
|
+
from google.adk.tools.tool_context import ToolContext
|
|
4
|
+
from app.agents.tools.github_mcp import github_mcp
|
|
5
|
+
from app.services.build_model_service import build_model
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def finish_discussion(tool_context: ToolContext):
|
|
9
|
+
"""Signals that the agent has successfully contributed to the discussion."""
|
|
10
|
+
tool_context.actions.escalate = True
|
|
11
|
+
return {"status": "contribution_posted"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
base_agent = LlmAgent(
|
|
15
|
+
name="IssueAdvisorAgent",
|
|
16
|
+
model=build_model(),
|
|
17
|
+
instruction="""
|
|
18
|
+
You are a Technical Advisor specializing in GitHub Issues. Your goal is to provide deep technical insights on reported problems or feature requests.
|
|
19
|
+
|
|
20
|
+
STEP 1: GATHER CONTEXT
|
|
21
|
+
- Fetch the Issue description and ALL existing comments.
|
|
22
|
+
- Search the codebase using relevant keywords from the issue to identify the specific files or functions involved.
|
|
23
|
+
|
|
24
|
+
STEP 2: ANALYZE
|
|
25
|
+
- Evaluate if the reported issue is a bug, a performance bottleneck, or a feature request.
|
|
26
|
+
- Propose a technical strategy or root cause analysis based on the codebase search.
|
|
27
|
+
- Acknowledge any previous comments to maintain a collaborative tone.
|
|
28
|
+
|
|
29
|
+
STEP 3: POST COMMENT
|
|
30
|
+
- Use the GitHub MCP tool to post your technical findings as a comment.
|
|
31
|
+
|
|
32
|
+
STRICT RULES:
|
|
33
|
+
- Do not look at Pull Requests. Never modify files or create branches.
|
|
34
|
+
- Do not offer to draft code changes.
|
|
35
|
+
""",
|
|
36
|
+
output_key="worker_output",
|
|
37
|
+
tools=[github_mcp()],
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
verifier_agent = LlmAgent(
|
|
41
|
+
name="ActionVerifier",
|
|
42
|
+
model=build_model(),
|
|
43
|
+
instruction="""
|
|
44
|
+
Review the 'worker_output'.
|
|
45
|
+
|
|
46
|
+
If the output mentions it is a Pull Request:
|
|
47
|
+
- Immediately call 'finish_discussion' to stop the loop.
|
|
48
|
+
If the text indicates a GitHub comment was successfully submitted via a tool call, run 'finish_discussion'.
|
|
49
|
+
If the text contains a technical analysis but NO evidence of a tool call (like 'comment_posted'),
|
|
50
|
+
explicitly command the agent: 'I see your analysis. You must now use the GitHub MCP tool to post this as a comment on the issue.'
|
|
51
|
+
""",
|
|
52
|
+
tools=[finish_discussion],
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
suggestion_agent = LoopAgent(
|
|
56
|
+
name="DiscussionAgent",
|
|
57
|
+
sub_agents=[base_agent, verifier_agent],
|
|
58
|
+
max_iterations=2,
|
|
59
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import keyring
|
|
2
|
+
from google.adk.tools.mcp_tool import McpToolset
|
|
3
|
+
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPServerParams
|
|
4
|
+
|
|
5
|
+
MCP_URL = "https://api.githubcopilot.com/mcp/"
|
|
6
|
+
SERVICE_NAME = "github-agent"
|
|
7
|
+
TOKEN_KEY = "github_token"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def github_mcp():
|
|
11
|
+
token = keyring.get_password(SERVICE_NAME, TOKEN_KEY)
|
|
12
|
+
|
|
13
|
+
return McpToolset(
|
|
14
|
+
connection_params=StreamableHTTPServerParams(
|
|
15
|
+
timeout=120,
|
|
16
|
+
url=MCP_URL,
|
|
17
|
+
headers={
|
|
18
|
+
"Authorization": f"Bearer {token}",
|
|
19
|
+
"X-MCP-Toolsets": "all",
|
|
20
|
+
"X-MCP-Readonly": "false",
|
|
21
|
+
},
|
|
22
|
+
),
|
|
23
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from app.workflows.agent_workflow import agent_workflow
|
|
2
|
+
import typer
|
|
3
|
+
import asyncio
|
|
4
|
+
from app.cli.inputs import (
|
|
5
|
+
ask_repo_url,
|
|
6
|
+
ask_agent_type,
|
|
7
|
+
ask_llm_model,
|
|
8
|
+
ask_github_token,
|
|
9
|
+
)
|
|
10
|
+
from app.cli.llm import ask_llm_token
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from rich.panel import Panel
|
|
13
|
+
from rich import box
|
|
14
|
+
from importlib.metadata import version
|
|
15
|
+
from app.cli.spinner import run_with_spinner
|
|
16
|
+
|
|
17
|
+
console = Console()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def run():
|
|
21
|
+
console.print(
|
|
22
|
+
Panel(
|
|
23
|
+
f"[bold cyan]CodPilot[/bold cyan] [green]v{version('codpilot')}[/green]\n"
|
|
24
|
+
"[dim]Autonomous coding agent for GitHub[/dim]",
|
|
25
|
+
box=box.DOUBLE,
|
|
26
|
+
border_style="cyan",
|
|
27
|
+
padding=(1, 4),
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
agent_type, description = ask_agent_type()
|
|
31
|
+
repo_url = ask_repo_url(agent_type)
|
|
32
|
+
model = ask_llm_model()
|
|
33
|
+
ask_llm_token(model)
|
|
34
|
+
ask_github_token()
|
|
35
|
+
|
|
36
|
+
asyncio.run(
|
|
37
|
+
run_with_spinner(
|
|
38
|
+
agent_workflow(
|
|
39
|
+
repo_url=repo_url, agent_type=agent_type, description=description
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
typer.echo("✅ Execution completed")
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import questionary
|
|
2
|
+
import keyring
|
|
3
|
+
import requests
|
|
4
|
+
import time
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from app.cli.llm import ask_llm_token
|
|
8
|
+
|
|
9
|
+
WORKFLOW_OPTIONS = {
|
|
10
|
+
"review_pr": "Review PR",
|
|
11
|
+
"create_feature": "Create a new feature",
|
|
12
|
+
"suggest_changes": "Add your suggestions to the Issue",
|
|
13
|
+
}
|
|
14
|
+
LLM_MODELS = ["Gemini", "OpenAI", "Anthropic"]
|
|
15
|
+
SERVICE_NAME = "github-agent"
|
|
16
|
+
LLM_MODEL_KEY = "llm_model"
|
|
17
|
+
LLM_TOKEN_KEY = "llm_api_token"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def ask_repo_url(agent_type):
|
|
21
|
+
if agent_type == "create_feature":
|
|
22
|
+
msg = "Enter the GitHub repository URL:"
|
|
23
|
+
elif agent_type == "suggest_changes":
|
|
24
|
+
msg = "Enter the GitHub Issue URL:"
|
|
25
|
+
else:
|
|
26
|
+
msg = "Enter the GitHub PR URL:"
|
|
27
|
+
|
|
28
|
+
repo_url = questionary.text(
|
|
29
|
+
msg,
|
|
30
|
+
).ask()
|
|
31
|
+
|
|
32
|
+
if not repo_url:
|
|
33
|
+
typer.echo("⛔️ URL is required")
|
|
34
|
+
raise SystemExit(1)
|
|
35
|
+
|
|
36
|
+
if not repo_url.startswith("https://github.com/"):
|
|
37
|
+
typer.echo("⛔️ Invalid URL")
|
|
38
|
+
raise SystemExit(1)
|
|
39
|
+
|
|
40
|
+
return repo_url
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def ask_agent_type():
|
|
44
|
+
choice = questionary.select(
|
|
45
|
+
"Select mode:",
|
|
46
|
+
choices=[
|
|
47
|
+
questionary.Choice(title=label, value=key)
|
|
48
|
+
for key, label in WORKFLOW_OPTIONS.items()
|
|
49
|
+
],
|
|
50
|
+
).ask()
|
|
51
|
+
|
|
52
|
+
if not choice:
|
|
53
|
+
typer.echo("Mode is required")
|
|
54
|
+
raise SystemExit(1)
|
|
55
|
+
|
|
56
|
+
description = None
|
|
57
|
+
if choice == "create_feature":
|
|
58
|
+
description = questionary.text(
|
|
59
|
+
"Enter the details of the feature you want to create:",
|
|
60
|
+
).ask()
|
|
61
|
+
|
|
62
|
+
if not description:
|
|
63
|
+
typer.echo("Description is required")
|
|
64
|
+
raise SystemExit(1)
|
|
65
|
+
|
|
66
|
+
return choice, description
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def ask_llm_model():
|
|
70
|
+
selected_model = keyring.get_password(SERVICE_NAME, LLM_MODEL_KEY)
|
|
71
|
+
|
|
72
|
+
if selected_model:
|
|
73
|
+
typer.echo(f"Using LLM model {selected_model}")
|
|
74
|
+
return selected_model
|
|
75
|
+
|
|
76
|
+
model = questionary.select(
|
|
77
|
+
"Select LLM model:",
|
|
78
|
+
choices=LLM_MODELS,
|
|
79
|
+
).ask()
|
|
80
|
+
|
|
81
|
+
if not model:
|
|
82
|
+
typer.echo("LLM model is required")
|
|
83
|
+
raise SystemExit(1)
|
|
84
|
+
|
|
85
|
+
keyring.set_password(SERVICE_NAME, LLM_MODEL_KEY, model)
|
|
86
|
+
|
|
87
|
+
return model
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def ask_github_token():
|
|
91
|
+
token = keyring.get_password(SERVICE_NAME, "github_token")
|
|
92
|
+
|
|
93
|
+
if token:
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
token = questionary.password("Enter your GitHub API token:").ask()
|
|
97
|
+
|
|
98
|
+
if not token:
|
|
99
|
+
typer.echo("⛔️ GitHub token is required")
|
|
100
|
+
raise SystemExit(1)
|
|
101
|
+
|
|
102
|
+
if _validate_github_token(token):
|
|
103
|
+
keyring.set_password(SERVICE_NAME, "github_token", token)
|
|
104
|
+
time.sleep(1)
|
|
105
|
+
else:
|
|
106
|
+
typer.echo("⛔️ Invalid GitHub token")
|
|
107
|
+
raise SystemExit(1)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def reset_github_token():
|
|
111
|
+
existing = keyring.get_password(SERVICE_NAME, "github_token")
|
|
112
|
+
|
|
113
|
+
if not existing:
|
|
114
|
+
typer.echo("⚠️ No GitHub token found in keyring.")
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
confirm = questionary.confirm(
|
|
118
|
+
"Are you sure you want to reset the stored GitHub token?"
|
|
119
|
+
).ask()
|
|
120
|
+
|
|
121
|
+
if not confirm:
|
|
122
|
+
typer.echo("ℹ️ Token reset cancelled.")
|
|
123
|
+
return
|
|
124
|
+
|
|
125
|
+
keyring.delete_password(SERVICE_NAME, "github_token")
|
|
126
|
+
typer.echo("🗑️ GitHub token removed.")
|
|
127
|
+
|
|
128
|
+
ask_github_token()
|
|
129
|
+
typer.echo("GitHub token has been reset successfully.")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def change_llm_model():
|
|
133
|
+
existing = keyring.get_password(SERVICE_NAME, LLM_MODEL_KEY)
|
|
134
|
+
|
|
135
|
+
if not existing:
|
|
136
|
+
typer.echo("⚠️ No LLM model found.")
|
|
137
|
+
return
|
|
138
|
+
|
|
139
|
+
confirm = questionary.confirm(
|
|
140
|
+
"Are you sure you want to change the LLM model?"
|
|
141
|
+
).ask()
|
|
142
|
+
|
|
143
|
+
if not confirm:
|
|
144
|
+
typer.echo("ℹ️ Change LLM model cancelled.")
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
keyring.delete_password(SERVICE_NAME, LLM_MODEL_KEY)
|
|
148
|
+
model = ask_llm_model()
|
|
149
|
+
if keyring.get_password(SERVICE_NAME, LLM_TOKEN_KEY):
|
|
150
|
+
keyring.delete_password(SERVICE_NAME, LLM_TOKEN_KEY)
|
|
151
|
+
|
|
152
|
+
ask_llm_token(model)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _validate_github_token(token: str) -> bool:
|
|
156
|
+
try:
|
|
157
|
+
resp = requests.get(
|
|
158
|
+
"https://api.github.com/user",
|
|
159
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
160
|
+
timeout=5,
|
|
161
|
+
)
|
|
162
|
+
return resp.status_code == 200
|
|
163
|
+
except requests.RequestException:
|
|
164
|
+
return False
|