codemaster-cli 1.0.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.
Files changed (174) hide show
  1. codemaster_cli-1.0.1.dist-info/METADATA +645 -0
  2. codemaster_cli-1.0.1.dist-info/RECORD +174 -0
  3. codemaster_cli-1.0.1.dist-info/WHEEL +4 -0
  4. codemaster_cli-1.0.1.dist-info/entry_points.txt +3 -0
  5. vibe/__init__.py +6 -0
  6. vibe/acp/__init__.py +0 -0
  7. vibe/acp/acp_agent_loop.py +746 -0
  8. vibe/acp/entrypoint.py +81 -0
  9. vibe/acp/tools/__init__.py +0 -0
  10. vibe/acp/tools/base.py +100 -0
  11. vibe/acp/tools/builtins/bash.py +134 -0
  12. vibe/acp/tools/builtins/read_file.py +54 -0
  13. vibe/acp/tools/builtins/search_replace.py +129 -0
  14. vibe/acp/tools/builtins/todo.py +65 -0
  15. vibe/acp/tools/builtins/write_file.py +98 -0
  16. vibe/acp/tools/session_update.py +118 -0
  17. vibe/acp/utils.py +213 -0
  18. vibe/cli/__init__.py +0 -0
  19. vibe/cli/autocompletion/__init__.py +0 -0
  20. vibe/cli/autocompletion/base.py +22 -0
  21. vibe/cli/autocompletion/path_completion.py +177 -0
  22. vibe/cli/autocompletion/slash_command.py +99 -0
  23. vibe/cli/cli.py +229 -0
  24. vibe/cli/clipboard.py +69 -0
  25. vibe/cli/commands.py +116 -0
  26. vibe/cli/entrypoint.py +173 -0
  27. vibe/cli/history_manager.py +91 -0
  28. vibe/cli/plan_offer/adapters/http_whoami_gateway.py +67 -0
  29. vibe/cli/plan_offer/decide_plan_offer.py +87 -0
  30. vibe/cli/plan_offer/ports/whoami_gateway.py +23 -0
  31. vibe/cli/terminal_setup.py +323 -0
  32. vibe/cli/textual_ui/__init__.py +0 -0
  33. vibe/cli/textual_ui/ansi_markdown.py +58 -0
  34. vibe/cli/textual_ui/app.py +1546 -0
  35. vibe/cli/textual_ui/app.tcss +1020 -0
  36. vibe/cli/textual_ui/external_editor.py +32 -0
  37. vibe/cli/textual_ui/handlers/__init__.py +5 -0
  38. vibe/cli/textual_ui/handlers/event_handler.py +147 -0
  39. vibe/cli/textual_ui/widgets/__init__.py +0 -0
  40. vibe/cli/textual_ui/widgets/approval_app.py +192 -0
  41. vibe/cli/textual_ui/widgets/banner/banner.py +85 -0
  42. vibe/cli/textual_ui/widgets/banner/petit_chat.py +176 -0
  43. vibe/cli/textual_ui/widgets/braille_renderer.py +58 -0
  44. vibe/cli/textual_ui/widgets/chat_input/__init__.py +7 -0
  45. vibe/cli/textual_ui/widgets/chat_input/body.py +214 -0
  46. vibe/cli/textual_ui/widgets/chat_input/completion_manager.py +58 -0
  47. vibe/cli/textual_ui/widgets/chat_input/completion_popup.py +43 -0
  48. vibe/cli/textual_ui/widgets/chat_input/container.py +195 -0
  49. vibe/cli/textual_ui/widgets/chat_input/text_area.py +365 -0
  50. vibe/cli/textual_ui/widgets/compact.py +41 -0
  51. vibe/cli/textual_ui/widgets/config_app.py +171 -0
  52. vibe/cli/textual_ui/widgets/context_progress.py +30 -0
  53. vibe/cli/textual_ui/widgets/load_more.py +43 -0
  54. vibe/cli/textual_ui/widgets/loading.py +201 -0
  55. vibe/cli/textual_ui/widgets/messages.py +277 -0
  56. vibe/cli/textual_ui/widgets/no_markup_static.py +11 -0
  57. vibe/cli/textual_ui/widgets/path_display.py +28 -0
  58. vibe/cli/textual_ui/widgets/proxy_setup_app.py +127 -0
  59. vibe/cli/textual_ui/widgets/question_app.py +496 -0
  60. vibe/cli/textual_ui/widgets/spinner.py +194 -0
  61. vibe/cli/textual_ui/widgets/status_message.py +76 -0
  62. vibe/cli/textual_ui/widgets/teleport_message.py +31 -0
  63. vibe/cli/textual_ui/widgets/tool_widgets.py +371 -0
  64. vibe/cli/textual_ui/widgets/tools.py +201 -0
  65. vibe/cli/textual_ui/windowing/__init__.py +29 -0
  66. vibe/cli/textual_ui/windowing/history.py +105 -0
  67. vibe/cli/textual_ui/windowing/history_windowing.py +71 -0
  68. vibe/cli/textual_ui/windowing/state.py +105 -0
  69. vibe/cli/update_notifier/__init__.py +47 -0
  70. vibe/cli/update_notifier/adapters/filesystem_update_cache_repository.py +59 -0
  71. vibe/cli/update_notifier/adapters/github_update_gateway.py +101 -0
  72. vibe/cli/update_notifier/adapters/pypi_update_gateway.py +107 -0
  73. vibe/cli/update_notifier/ports/update_cache_repository.py +16 -0
  74. vibe/cli/update_notifier/ports/update_gateway.py +53 -0
  75. vibe/cli/update_notifier/update.py +139 -0
  76. vibe/cli/update_notifier/whats_new.py +49 -0
  77. vibe/core/__init__.py +5 -0
  78. vibe/core/agent_loop.py +1075 -0
  79. vibe/core/agents/__init__.py +31 -0
  80. vibe/core/agents/manager.py +166 -0
  81. vibe/core/agents/models.py +143 -0
  82. vibe/core/auth/__init__.py +6 -0
  83. vibe/core/auth/crypto.py +137 -0
  84. vibe/core/auth/github.py +178 -0
  85. vibe/core/autocompletion/__init__.py +0 -0
  86. vibe/core/autocompletion/completers.py +257 -0
  87. vibe/core/autocompletion/file_indexer/__init__.py +10 -0
  88. vibe/core/autocompletion/file_indexer/ignore_rules.py +156 -0
  89. vibe/core/autocompletion/file_indexer/indexer.py +179 -0
  90. vibe/core/autocompletion/file_indexer/store.py +169 -0
  91. vibe/core/autocompletion/file_indexer/watcher.py +71 -0
  92. vibe/core/autocompletion/fuzzy.py +189 -0
  93. vibe/core/autocompletion/path_prompt.py +108 -0
  94. vibe/core/autocompletion/path_prompt_adapter.py +149 -0
  95. vibe/core/config.py +983 -0
  96. vibe/core/config_PATCH_INSTRUCTIONS.md +77 -0
  97. vibe/core/llm/__init__.py +0 -0
  98. vibe/core/llm/backend/anthropic.py +630 -0
  99. vibe/core/llm/backend/base.py +38 -0
  100. vibe/core/llm/backend/factory.py +7 -0
  101. vibe/core/llm/backend/generic.py +425 -0
  102. vibe/core/llm/backend/mistral.py +381 -0
  103. vibe/core/llm/backend/vertex.py +115 -0
  104. vibe/core/llm/exceptions.py +195 -0
  105. vibe/core/llm/format.py +184 -0
  106. vibe/core/llm/message_utils.py +24 -0
  107. vibe/core/llm/types.py +120 -0
  108. vibe/core/middleware.py +209 -0
  109. vibe/core/output_formatters.py +85 -0
  110. vibe/core/paths/__init__.py +0 -0
  111. vibe/core/paths/config_paths.py +68 -0
  112. vibe/core/paths/global_paths.py +40 -0
  113. vibe/core/programmatic.py +56 -0
  114. vibe/core/prompts/__init__.py +33 -0
  115. vibe/core/prompts/cli.md +111 -0
  116. vibe/core/prompts/compact.md +48 -0
  117. vibe/core/prompts/dangerous_directory.md +5 -0
  118. vibe/core/prompts/explore.md +50 -0
  119. vibe/core/prompts/gitmaster.md +38 -0
  120. vibe/core/prompts/project_context.md +8 -0
  121. vibe/core/prompts/tests.md +1 -0
  122. vibe/core/proxy_setup.py +65 -0
  123. vibe/core/session/session_loader.py +222 -0
  124. vibe/core/session/session_logger.py +318 -0
  125. vibe/core/session/session_migration.py +41 -0
  126. vibe/core/skills/__init__.py +7 -0
  127. vibe/core/skills/manager.py +132 -0
  128. vibe/core/skills/models.py +92 -0
  129. vibe/core/skills/parser.py +39 -0
  130. vibe/core/system_prompt.py +466 -0
  131. vibe/core/telemetry/__init__.py +0 -0
  132. vibe/core/telemetry/send.py +185 -0
  133. vibe/core/teleport/errors.py +9 -0
  134. vibe/core/teleport/git.py +196 -0
  135. vibe/core/teleport/nuage.py +180 -0
  136. vibe/core/teleport/teleport.py +208 -0
  137. vibe/core/teleport/types.py +54 -0
  138. vibe/core/tools/base.py +338 -0
  139. vibe/core/tools/builtins/ask_user_question.py +134 -0
  140. vibe/core/tools/builtins/bash.py +454 -0
  141. vibe/core/tools/builtins/git_clone.py +861 -0
  142. vibe/core/tools/builtins/grep.py +310 -0
  143. vibe/core/tools/builtins/prompts/__init__.py +0 -0
  144. vibe/core/tools/builtins/prompts/ask_user_question.md +84 -0
  145. vibe/core/tools/builtins/prompts/bash.md +73 -0
  146. vibe/core/tools/builtins/prompts/git_clone.md +43 -0
  147. vibe/core/tools/builtins/prompts/gitmaster.md +38 -0
  148. vibe/core/tools/builtins/prompts/grep.md +4 -0
  149. vibe/core/tools/builtins/prompts/read_file.md +13 -0
  150. vibe/core/tools/builtins/prompts/search_replace.md +43 -0
  151. vibe/core/tools/builtins/prompts/task.md +24 -0
  152. vibe/core/tools/builtins/prompts/todo.md +199 -0
  153. vibe/core/tools/builtins/prompts/write_file.md +42 -0
  154. vibe/core/tools/builtins/read_file.py +222 -0
  155. vibe/core/tools/builtins/search_replace.py +456 -0
  156. vibe/core/tools/builtins/task.py +154 -0
  157. vibe/core/tools/builtins/todo.py +134 -0
  158. vibe/core/tools/builtins/write_file.py +160 -0
  159. vibe/core/tools/manager.py +341 -0
  160. vibe/core/tools/mcp.py +397 -0
  161. vibe/core/tools/ui.py +68 -0
  162. vibe/core/trusted_folders.py +86 -0
  163. vibe/core/types.py +401 -0
  164. vibe/core/utils.py +396 -0
  165. vibe/setup/onboarding/__init__.py +39 -0
  166. vibe/setup/onboarding/base.py +14 -0
  167. vibe/setup/onboarding/onboarding.tcss +134 -0
  168. vibe/setup/onboarding/screens/__init__.py +5 -0
  169. vibe/setup/onboarding/screens/api_key.py +200 -0
  170. vibe/setup/onboarding/screens/provider_selection.py +184 -0
  171. vibe/setup/onboarding/screens/welcome.py +136 -0
  172. vibe/setup/trusted_folders/trust_folder_dialog.py +180 -0
  173. vibe/setup/trusted_folders/trust_folder_dialog.tcss +83 -0
  174. vibe/whats_new.md +5 -0
@@ -0,0 +1,310 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from collections.abc import AsyncGenerator
5
+ from enum import StrEnum, auto
6
+ from pathlib import Path
7
+ import shutil
8
+ from typing import TYPE_CHECKING, ClassVar
9
+
10
+ from pydantic import BaseModel, Field
11
+
12
+ from vibe.core.tools.base import (
13
+ BaseTool,
14
+ BaseToolConfig,
15
+ BaseToolState,
16
+ InvokeContext,
17
+ ToolError,
18
+ ToolPermission,
19
+ )
20
+ from vibe.core.tools.ui import ToolCallDisplay, ToolResultDisplay, ToolUIData
21
+ from vibe.core.types import ToolStreamEvent
22
+
23
+ if TYPE_CHECKING:
24
+ from vibe.core.types import ToolCallEvent, ToolResultEvent
25
+
26
+
27
+ class GrepBackend(StrEnum):
28
+ RIPGREP = auto()
29
+ GNU_GREP = auto()
30
+
31
+
32
+ class GrepToolConfig(BaseToolConfig):
33
+ permission: ToolPermission = ToolPermission.ALWAYS
34
+
35
+ max_output_bytes: int = Field(
36
+ default=64_000, description="Hard cap for the total size of matched lines."
37
+ )
38
+ default_max_matches: int = Field(
39
+ default=100, description="Default maximum number of matches to return."
40
+ )
41
+ default_timeout: int = Field(
42
+ default=60, description="Default timeout for the search command in seconds."
43
+ )
44
+ exclude_patterns: list[str] = Field(
45
+ default=[
46
+ ".venv/",
47
+ "venv/",
48
+ ".env/",
49
+ "env/",
50
+ "node_modules/",
51
+ ".git/",
52
+ "__pycache__/",
53
+ ".pytest_cache/",
54
+ ".mypy_cache/",
55
+ ".tox/",
56
+ ".nox/",
57
+ ".coverage/",
58
+ "htmlcov/",
59
+ "dist/",
60
+ "build/",
61
+ ".idea/",
62
+ ".vscode/",
63
+ "*.egg-info",
64
+ "*.pyc",
65
+ "*.pyo",
66
+ "*.pyd",
67
+ ".DS_Store",
68
+ "Thumbs.db",
69
+ ],
70
+ description="List of glob patterns to exclude from search (dirs should end with /).",
71
+ )
72
+ codeignore_file: str = Field(
73
+ default=".vibeignore",
74
+ description="Name of the file to read for additional exclusion patterns.",
75
+ )
76
+
77
+
78
+ class GrepState(BaseToolState):
79
+ search_history: list[str] = Field(default_factory=list)
80
+
81
+
82
+ class GrepArgs(BaseModel):
83
+ pattern: str
84
+ path: str = "."
85
+ max_matches: int | None = Field(
86
+ default=None, description="Override the default maximum number of matches."
87
+ )
88
+ use_default_ignore: bool = Field(
89
+ default=True, description="Whether to respect .gitignore and .ignore files."
90
+ )
91
+
92
+
93
+ class GrepResult(BaseModel):
94
+ matches: str
95
+ match_count: int
96
+ was_truncated: bool = Field(
97
+ description="True if output was cut short by max_matches or max_output_bytes."
98
+ )
99
+
100
+
101
+ class Grep(
102
+ BaseTool[GrepArgs, GrepResult, GrepToolConfig, GrepState],
103
+ ToolUIData[GrepArgs, GrepResult],
104
+ ):
105
+ description: ClassVar[str] = (
106
+ "Recursively search files for a regex pattern using ripgrep (rg) or grep. "
107
+ "Respects .gitignore and .codeignore files by default when using ripgrep."
108
+ )
109
+
110
+ def _detect_backend(self) -> GrepBackend:
111
+ if shutil.which("rg"):
112
+ return GrepBackend.RIPGREP
113
+ if shutil.which("grep"):
114
+ return GrepBackend.GNU_GREP
115
+ raise ToolError(
116
+ "Neither ripgrep (rg) nor grep is installed. "
117
+ "Please install ripgrep: https://github.com/BurntSushi/ripgrep#installation"
118
+ )
119
+
120
+ async def run(
121
+ self, args: GrepArgs, ctx: InvokeContext | None = None
122
+ ) -> AsyncGenerator[ToolStreamEvent | GrepResult, None]:
123
+ backend = self._detect_backend()
124
+ self._validate_args(args)
125
+ self.state.search_history.append(args.pattern)
126
+
127
+ exclude_patterns = self._collect_exclude_patterns()
128
+ cmd = self._build_command(args, exclude_patterns, backend)
129
+ stdout = await self._execute_search(cmd)
130
+
131
+ yield self._parse_output(
132
+ stdout, args.max_matches or self.config.default_max_matches
133
+ )
134
+
135
+ def _validate_args(self, args: GrepArgs) -> None:
136
+ if not args.pattern.strip():
137
+ raise ToolError("Empty search pattern provided.")
138
+
139
+ path_obj = Path(args.path).expanduser()
140
+ if not path_obj.is_absolute():
141
+ path_obj = Path.cwd() / path_obj
142
+
143
+ if not path_obj.exists():
144
+ raise ToolError(f"Path does not exist: {args.path}")
145
+
146
+ def _collect_exclude_patterns(self) -> list[str]:
147
+ patterns = list(self.config.exclude_patterns)
148
+
149
+ codeignore_path = Path.cwd() / self.config.codeignore_file
150
+ if codeignore_path.is_file():
151
+ patterns.extend(self._load_codeignore_patterns(codeignore_path))
152
+
153
+ return patterns
154
+
155
+ def _load_codeignore_patterns(self, codeignore_path: Path) -> list[str]:
156
+ patterns = []
157
+ try:
158
+ content = codeignore_path.read_text("utf-8")
159
+ for line in content.splitlines():
160
+ line = line.strip()
161
+ if line and not line.startswith("#"):
162
+ patterns.append(line)
163
+ except OSError:
164
+ pass
165
+
166
+ return patterns
167
+
168
+ def _build_command(
169
+ self, args: GrepArgs, exclude_patterns: list[str], backend: GrepBackend
170
+ ) -> list[str]:
171
+ if backend == GrepBackend.RIPGREP:
172
+ return self._build_ripgrep_command(args, exclude_patterns)
173
+ return self._build_gnu_grep_command(args, exclude_patterns)
174
+
175
+ def _build_ripgrep_command(
176
+ self, args: GrepArgs, exclude_patterns: list[str]
177
+ ) -> list[str]:
178
+ max_matches = args.max_matches or self.config.default_max_matches
179
+
180
+ cmd = [
181
+ "rg",
182
+ "--line-number",
183
+ "--no-heading",
184
+ "--smart-case",
185
+ "--no-binary",
186
+ # Request one extra to detect truncation
187
+ "--max-count",
188
+ str(max_matches + 1),
189
+ ]
190
+
191
+ if not args.use_default_ignore:
192
+ cmd.append("--no-ignore")
193
+
194
+ for pattern in exclude_patterns:
195
+ cmd.extend(["--glob", f"!{pattern}"])
196
+
197
+ cmd.extend(["-e", args.pattern, args.path])
198
+
199
+ return cmd
200
+
201
+ def _build_gnu_grep_command(
202
+ self, args: GrepArgs, exclude_patterns: list[str]
203
+ ) -> list[str]:
204
+ max_matches = args.max_matches or self.config.default_max_matches
205
+
206
+ cmd = ["grep", "-r", "-n", "-I", "-E", f"--max-count={max_matches + 1}"]
207
+
208
+ if args.pattern.islower():
209
+ cmd.append("-i")
210
+
211
+ for pattern in exclude_patterns:
212
+ if pattern.endswith("/"):
213
+ dir_pattern = pattern.rstrip("/")
214
+ cmd.append(f"--exclude-dir={dir_pattern}")
215
+ else:
216
+ cmd.append(f"--exclude={pattern}")
217
+
218
+ cmd.extend(["-e", args.pattern, args.path])
219
+
220
+ return cmd
221
+
222
+ async def _execute_search(self, cmd: list[str]) -> str:
223
+ try:
224
+ proc = await asyncio.create_subprocess_exec(
225
+ *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
226
+ )
227
+
228
+ try:
229
+ stdout_bytes, stderr_bytes = await asyncio.wait_for(
230
+ proc.communicate(), timeout=self.config.default_timeout
231
+ )
232
+ except TimeoutError:
233
+ proc.kill()
234
+ await proc.wait()
235
+ raise ToolError(
236
+ f"Search timed out after {self.config.default_timeout}s"
237
+ )
238
+
239
+ stdout = (
240
+ stdout_bytes.decode("utf-8", errors="ignore") if stdout_bytes else ""
241
+ )
242
+ stderr = (
243
+ stderr_bytes.decode("utf-8", errors="ignore") if stderr_bytes else ""
244
+ )
245
+
246
+ if proc.returncode not in {0, 1}:
247
+ error_msg = stderr or f"Process exited with code {proc.returncode}"
248
+ raise ToolError(f"grep error: {error_msg}")
249
+
250
+ return stdout
251
+
252
+ except ToolError:
253
+ raise
254
+ except Exception as exc:
255
+ raise ToolError(f"Error running grep: {exc}") from exc
256
+
257
+ def _parse_output(self, stdout: str, max_matches: int) -> GrepResult:
258
+ output_lines = stdout.splitlines() if stdout else []
259
+
260
+ truncated_lines = output_lines[:max_matches]
261
+ truncated_output = "\n".join(truncated_lines)
262
+
263
+ was_truncated = (
264
+ len(output_lines) > max_matches
265
+ or len(truncated_output) > self.config.max_output_bytes
266
+ )
267
+
268
+ final_output = truncated_output[: self.config.max_output_bytes]
269
+
270
+ return GrepResult(
271
+ matches=final_output,
272
+ match_count=len(truncated_lines),
273
+ was_truncated=was_truncated,
274
+ )
275
+
276
+ @classmethod
277
+ def get_call_display(cls, event: ToolCallEvent) -> ToolCallDisplay:
278
+ if not isinstance(event.args, GrepArgs):
279
+ return ToolCallDisplay(summary="grep")
280
+
281
+ summary = f"Grepping '{event.args.pattern}'"
282
+ if event.args.path != ".":
283
+ summary += f" in {event.args.path}"
284
+ if event.args.max_matches:
285
+ summary += f" (max {event.args.max_matches} matches)"
286
+ if not event.args.use_default_ignore:
287
+ summary += " [no-ignore]"
288
+
289
+ return ToolCallDisplay(summary=summary)
290
+
291
+ @classmethod
292
+ def get_result_display(cls, event: ToolResultEvent) -> ToolResultDisplay:
293
+ if not isinstance(event.result, GrepResult):
294
+ return ToolResultDisplay(
295
+ success=False, message=event.error or event.skip_reason or "No result"
296
+ )
297
+
298
+ message = f"Found {event.result.match_count} matches"
299
+ if event.result.was_truncated:
300
+ message += " (truncated)"
301
+
302
+ warnings = []
303
+ if event.result.was_truncated:
304
+ warnings.append("Output was truncated due to size/match limits")
305
+
306
+ return ToolResultDisplay(success=True, message=message, warnings=warnings)
307
+
308
+ @classmethod
309
+ def get_status_text(cls) -> str:
310
+ return "Searching files"
File without changes
@@ -0,0 +1,84 @@
1
+ Use `ask_user_question` to gather information from the user when you need clarification, want to validate assumptions, or need help making a decision. **Don't hesitate to use this tool** - it's better to ask than to guess wrong.
2
+
3
+ ## When to Use
4
+
5
+ - **Clarifying requirements**: Ambiguous instructions, unclear scope
6
+ - **Technical decisions**: Architecture choices, library selection, tradeoffs
7
+ - **Preference gathering**: UI style, naming conventions, approach options
8
+ - **Validation**: Confirming understanding before starting significant work
9
+ - **Multiple valid paths**: When several approaches could work and you want user input
10
+
11
+ ## Question Structure
12
+
13
+ Each question has these fields:
14
+
15
+ - `question`: The full question text (be specific and clear)
16
+ - `header`: A short label displayed as a chip (max 12 characters, e.g., "Auth", "Database", "Approach")
17
+ - `options`: 2-4 choices (an "Other" option is automatically added for free text)
18
+ - `multi_select`: Set to `true` if user can pick multiple options (default: `false`)
19
+
20
+ ### Options Structure
21
+
22
+ Each option has:
23
+ - `label`: Short display text (1-5 words)
24
+ - `description`: Brief explanation of what this choice means or its implications
25
+
26
+ ## Examples
27
+
28
+ **Single question with recommended option:**
29
+ ```json
30
+ {
31
+ "questions": [{
32
+ "question": "Which authentication method should we use?",
33
+ "header": "Auth",
34
+ "options": [
35
+ {"label": "JWT tokens (Recommended)", "description": "Stateless, scalable, works well with APIs"},
36
+ {"label": "Session cookies", "description": "Traditional approach, requires session storage"},
37
+ {"label": "OAuth 2.0", "description": "Third-party auth, more complex setup"}
38
+ ],
39
+ "multi_select": false
40
+ }]
41
+ }
42
+ ```
43
+
44
+ **Multiple questions (displayed as tabs):**
45
+ ```json
46
+ {
47
+ "questions": [
48
+ {
49
+ "question": "Which database should we use?",
50
+ "header": "Database",
51
+ "options": [
52
+ {"label": "PostgreSQL", "description": "Relational, ACID compliant"},
53
+ {"label": "MongoDB", "description": "Document store, flexible schema"}
54
+ ],
55
+ "multi_select": false
56
+ },
57
+ {
58
+ "question": "Which features should be included in v1?",
59
+ "header": "Features",
60
+ "options": [
61
+ {"label": "User auth", "description": "Login, signup, password reset"},
62
+ {"label": "Search", "description": "Full-text search across content"},
63
+ {"label": "Export", "description": "CSV and PDF export"}
64
+ ],
65
+ "multi_select": true
66
+ }
67
+ ]
68
+ }
69
+ ```
70
+
71
+ ## Key Constraints
72
+
73
+ - **Header max length**: 12 characters (keeps UI clean)
74
+ - **Options count**: 2-4 per question (plus automatic "Other")
75
+ - **Questions count**: 1-4 per call
76
+ - **Label length**: Keep to 1-5 words for readability
77
+
78
+ ## Tips
79
+
80
+ 1. **Put recommended option first** and add "(Recommended)" to its label
81
+ 2. **Use descriptive headers** that categorize the question type
82
+ 3. **Keep descriptions concise** but informative about tradeoffs
83
+ 4. **Use multi_select** when choices aren't mutually exclusive (e.g., features to include)
84
+ 5. **Ask early** - it's better to clarify before starting than to redo work
@@ -0,0 +1,73 @@
1
+ Use the `bash` tool to run one-off shell commands.
2
+
3
+ **Key characteristics:**
4
+ - **Stateless**: Each command runs independently in a fresh environment
5
+
6
+ **Timeout:**
7
+ - The `timeout` argument controls how long the command can run before being killed
8
+ - When `timeout` is not specified (or set to `None`), the config default is used
9
+ - If a command is timing out, do not hesitate to increase the timeout using the `timeout` argument
10
+
11
+ **IMPORTANT: Use dedicated tools if available instead of these bash commands:**
12
+
13
+ **File Operations - DO NOT USE:**
14
+ - `cat filename` → Use `read_file(path="filename")`
15
+ - `head -n 20 filename` → Use `read_file(path="filename", limit=20)`
16
+ - `tail -n 20 filename` → Read with offset: `read_file(path="filename", offset=<line_number>, limit=20)`
17
+ - `sed -n '100,200p' filename` → Use `read_file(path="filename", offset=99, limit=101)`
18
+ - `less`, `more`, `vim`, `nano` → Use `read_file` with offset/limit for navigation
19
+ - `echo "content" > file` → Use `write_file(path="file", content="content")`
20
+ - `echo "content" >> file` → Read first, then `write_file` with overwrite=true
21
+
22
+ **Search Operations - DO NOT USE:**
23
+ - `grep -r "pattern" .` → Use `grep(pattern="pattern", path=".")`
24
+ - `find . -name "*.py"` → Use `bash("ls -la")` for current dir or `grep` with appropriate pattern
25
+ - `ag`, `ack`, `rg` commands → Use the `grep` tool
26
+ - `locate` → Use `grep` tool
27
+
28
+ **File Modification - DO NOT USE:**
29
+ - `sed -i 's/old/new/g' file` → Use `search_replace` tool
30
+ - `awk` for file editing → Use `search_replace` tool
31
+ - Any in-place file editing → Use `search_replace` tool
32
+
33
+ **APPROPRIATE bash uses:**
34
+ - System information: `pwd`, `whoami`, `date`, `uname -a`
35
+ - Directory listings: `ls -la`, `tree` (if available)
36
+ - Git operations: `git status`, `git log --oneline -10`, `git diff`
37
+ - Process info: `ps aux | grep process`, `top -n 1`
38
+ - Network checks: `ping -c 1 google.com`, `curl -I https://example.com`
39
+ - Package management: `pip list`, `npm list`
40
+ - Environment checks: `env | grep VAR`, `which python`
41
+ - File metadata: `stat filename`, `file filename`, `wc -l filename`
42
+
43
+ **Example: Reading a large file efficiently**
44
+
45
+ WRONG:
46
+ ```bash
47
+ bash("cat large_file.txt") # May hit size limits
48
+ bash("head -1000 large_file.txt") # Inefficient
49
+ ```
50
+
51
+ RIGHT:
52
+ ```python
53
+ # First chunk
54
+ read_file(path="large_file.txt", limit=1000)
55
+ # If was_truncated=true, read next chunk
56
+ read_file(path="large_file.txt", offset=1000, limit=1000)
57
+ ```
58
+
59
+ **Example: Searching for patterns**
60
+
61
+ WRONG:
62
+ ```bash
63
+ bash("grep -r 'TODO' src/") # Don't use bash for grep
64
+ bash("find . -type f -name '*.py' | xargs grep 'import'") # Too complex
65
+ ```
66
+
67
+ RIGHT:
68
+ ```python
69
+ grep(pattern="TODO", path="src/")
70
+ grep(pattern="import", path=".")
71
+ ```
72
+
73
+ **Remember:** Bash is best for quick system checks and git operations. For file operations, searching, and editing, always use the dedicated tools when they are available.
@@ -0,0 +1,43 @@
1
+ ## git_clone
2
+
3
+ Clone a public GitHub repository into the current working directory.
4
+
5
+ ### Parameters
6
+
7
+ - `repo` (string, required): The GitHub repository to clone. Accepts:
8
+ - Full URL: `https://github.com/owner/repo`
9
+ - Full URL with .git: `https://github.com/owner/repo.git`
10
+ - Short form: `owner/repo`
11
+ - SSH URL: `git@github.com:owner/repo.git`
12
+ - `destination` (string, optional): Target directory name. Defaults to the repository name.
13
+ - `branch` (string, optional): Specific branch to clone. Defaults to the repository's default branch.
14
+ - `depth` (integer, optional): Create a shallow clone with the specified number of commits. Use `1` for the shallowest clone.
15
+ - `sparse_paths` (array of strings, optional): Only checkout specific directories/files. Useful for large monorepos.
16
+
17
+ ### Usage Guidelines
18
+
19
+ - Use this tool when the user asks to clone, download, fetch, or pull a GitHub repository.
20
+ - Always confirm the repository URL with the user if ambiguous.
21
+ - For large repositories, suggest using `depth: 1` for faster cloning.
22
+ - For monorepos where only a subdirectory is needed, use `sparse_paths`.
23
+ - The destination directory must not already exist.
24
+ - Only public GitHub repositories are supported.
25
+ - After cloning, briefly summarize what was cloned (branch, file count, top-level structure).
26
+
27
+ ### Examples
28
+
29
+ Clone a repository:
30
+
31
+ git_clone(repo="facebook/react")
32
+
33
+ Clone to a specific directory:
34
+
35
+ git_clone(repo="https://github.com/facebook/react", destination="react-source")
36
+
37
+ Shallow clone of a specific branch:
38
+
39
+ git_clone(repo="torvalds/linux", branch="v6.5", depth=1)
40
+
41
+ Sparse checkout (only specific directories):
42
+
43
+ git_clone(repo="google/jax", sparse_paths=["jax/numpy", "tests/numpy_test.py"])
@@ -0,0 +1,38 @@
1
+ You are GitMaster, a specialized agent within CodeMaster focused on cloning and exploring GitHub repositories.
2
+
3
+ ## Your Primary Capabilities
4
+
5
+ 1. **Repository Cloning**: You can clone any public GitHub repository using the `git_clone` tool.
6
+ 2. **Codebase Exploration**: After cloning, you help users understand the repository structure, key files, and architecture.
7
+ 3. **Smart Suggestions**: You proactively suggest optimal clone strategies (shallow vs full, sparse checkout for monorepos).
8
+
9
+ ## Workflow
10
+
11
+ When a user asks you to clone a repository:
12
+
13
+ 1. **Parse the request**: Extract the repository URL/identifier from the user's natural language request.
14
+ 2. **Confirm if needed**: If the request is ambiguous, ask for clarification using `ask_user_question`.
15
+ 3. **Optimize**: For repositories known to be large, suggest shallow cloning or sparse checkout.
16
+ 4. **Clone**: Use the `git_clone` tool with appropriate parameters.
17
+ 5. **Explore**: After cloning, automatically provide an overview of the repository:
18
+ - Read the README.md if it exists
19
+ - Summarize the project structure
20
+ - Identify the primary language/framework
21
+ - Note any setup instructions
22
+
23
+ ## Guidelines
24
+
25
+ - Always use the `git_clone` tool for cloning — never use `bash` with raw `git clone` commands.
26
+ - If the user provides just a repo name without an owner (e.g., "clone react"), ask which owner/organization they mean or suggest the most popular one.
27
+ - After cloning, offer to help explore specific parts of the codebase.
28
+ - If cloning fails, diagnose the issue and suggest solutions.
29
+ - You can use `grep`, `read_file`, and other exploration tools to help users understand cloned repositories.
30
+ - Track your progress using the `todo` tool when handling complex multi-step requests.
31
+ - You can delegate exploration tasks to subagents using the `task` tool.
32
+
33
+ ## Response Style
34
+
35
+ - Be concise but informative.
36
+ - Use emoji sparingly for status indicators (✅ success, ❌ error, 📦 repo info).
37
+ - When presenting repository structure, use tree-like formatting.
38
+ - Always confirm the clone location to the user.
@@ -0,0 +1,4 @@
1
+ Use `grep` to recursively search for a regular expression pattern in files.
2
+
3
+ - It's very fast and automatically ignores files that you should not read like .pyc files, .venv directories, etc.
4
+ - Use this to find where functions are defined, how variables are used, or to locate specific error messages.
@@ -0,0 +1,13 @@
1
+ Use `read_file` to read the content of a file. It's designed to handle large files safely.
2
+
3
+ - By default, it reads from the beginning of the file.
4
+ - Use `offset` (line number) and `limit` (number of lines) to read specific parts or chunks of a file. This is efficient for exploring large files.
5
+ - The result includes `was_truncated: true` if the file content was cut short due to size limits.
6
+
7
+ **Strategy for large files:**
8
+
9
+ 1. Call `read_file` with a `limit` (e.g., 1000 lines) to get the start of the file.
10
+ 2. If `was_truncated` is true, you know the file is large.
11
+ 3. To read the next chunk, call `read_file` again with an `offset`. For example, `offset=1000, limit=1000`.
12
+
13
+ This is more efficient than using `bash` with `cat` or `wc`.
@@ -0,0 +1,43 @@
1
+ Use `search_replace` to make targeted changes to files using SEARCH/REPLACE blocks. This tool finds exact text matches and replaces them.
2
+
3
+ Arguments:
4
+ - `file_path`: The path to the file to modify
5
+ - `content`: The SEARCH/REPLACE blocks defining the changes
6
+
7
+ The content format is:
8
+
9
+ ```
10
+ <<<<<<< SEARCH
11
+ [exact text to find in the file]
12
+ =======
13
+ [exact text to replace it with]
14
+ >>>>>>> REPLACE
15
+ ```
16
+
17
+ You can include multiple SEARCH/REPLACE blocks to make multiple changes to the same file:
18
+
19
+ ```
20
+ <<<<<<< SEARCH
21
+ def old_function():
22
+ return "old value"
23
+ =======
24
+ def new_function():
25
+ return "new value"
26
+ >>>>>>> REPLACE
27
+
28
+ <<<<<<< SEARCH
29
+ import os
30
+ =======
31
+ import os
32
+ import sys
33
+ >>>>>>> REPLACE
34
+ ```
35
+
36
+ IMPORTANT:
37
+
38
+ - The SEARCH text must match EXACTLY (including whitespace, indentation, and line endings)
39
+ - The SEARCH text must appear exactly once in the file - if it appears multiple times, the tool will error
40
+ - Use at least 5 equals signs (=====) between SEARCH and REPLACE sections
41
+ - The tool will provide detailed error messages showing context if search text is not found
42
+ - Each search/replace block is applied in order, so later blocks see the results of earlier ones
43
+ - Be careful with escape sequences in string literals - use \n not \\n for newlines in code
@@ -0,0 +1,24 @@
1
+ Use `task` to delegate work to a subagent for independent execution.
2
+
3
+ ## When to Use This Tool
4
+
5
+ - **Context management**: Delegate tasks that would consume too much main conversation context
6
+ - **Specialized work**: Use the appropriate subagent for the type of task (exploration, research, etc.)
7
+ - **Parallel execution**: Launch multiple subagents for independent tasks
8
+ - **Autonomous work**: Tasks that don't require back-and-forth with the user
9
+
10
+ ## Best Practices
11
+
12
+ 1. **Write clear, detailed task descriptions** - The subagent works autonomously, so provide enough context for it to succeed independently
13
+
14
+ 2. **Choose the right subagent** - Match the subagent to the task type (see available subagents in system prompt)
15
+
16
+ 3. **Prefer direct tools for simple operations** - If you know exactly which file to read or pattern to search, use those tools directly instead of spawning a subagent
17
+
18
+ 4. **Trust the subagent's judgment** - Let it explore and find information without micromanaging the approach
19
+
20
+ ## Limitations
21
+
22
+ - Subagents cannot write or modify files
23
+ - Subagents cannot ask the user questions
24
+ - Results are returned as text when the subagent completes