opsmith-cli 0.1.2a0__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 (55) hide show
  1. opsmith/__init__.py +0 -0
  2. opsmith/agent.py +243 -0
  3. opsmith/cloud_providers/__init__.py +10 -0
  4. opsmith/cloud_providers/aws.py +46 -0
  5. opsmith/cloud_providers/base.py +57 -0
  6. opsmith/cloud_providers/gcp.py +67 -0
  7. opsmith/constants.py +175 -0
  8. opsmith/deployer.py +236 -0
  9. opsmith/git_repo.py +66 -0
  10. opsmith/main.py +269 -0
  11. opsmith/prompts.py +76 -0
  12. opsmith/queries/tree-sitter-languages/README.md +7 -0
  13. opsmith/queries/tree-sitter-languages/arduino-tags.scm +5 -0
  14. opsmith/queries/tree-sitter-languages/c-tags.scm +9 -0
  15. opsmith/queries/tree-sitter-languages/c_sharp-tags.scm +46 -0
  16. opsmith/queries/tree-sitter-languages/chatito-tags.scm +16 -0
  17. opsmith/queries/tree-sitter-languages/commonlisp-tags.scm +122 -0
  18. opsmith/queries/tree-sitter-languages/cpp-tags.scm +15 -0
  19. opsmith/queries/tree-sitter-languages/csharp-tags.scm +26 -0
  20. opsmith/queries/tree-sitter-languages/d-tags.scm +26 -0
  21. opsmith/queries/tree-sitter-languages/dart-tags.scm +92 -0
  22. opsmith/queries/tree-sitter-languages/elisp-tags.scm +5 -0
  23. opsmith/queries/tree-sitter-languages/elixir-tags.scm +54 -0
  24. opsmith/queries/tree-sitter-languages/elm-tags.scm +19 -0
  25. opsmith/queries/tree-sitter-languages/gleam-tags.scm +41 -0
  26. opsmith/queries/tree-sitter-languages/go-tags.scm +42 -0
  27. opsmith/queries/tree-sitter-languages/hcl-tags.scm +77 -0
  28. opsmith/queries/tree-sitter-languages/java-tags.scm +20 -0
  29. opsmith/queries/tree-sitter-languages/javascript-tags.scm +88 -0
  30. opsmith/queries/tree-sitter-languages/kotlin-tags.scm +27 -0
  31. opsmith/queries/tree-sitter-languages/lua-tags.scm +34 -0
  32. opsmith/queries/tree-sitter-languages/ocaml-tags.scm +115 -0
  33. opsmith/queries/tree-sitter-languages/ocaml_interface-tags.scm +98 -0
  34. opsmith/queries/tree-sitter-languages/php-tags.scm +26 -0
  35. opsmith/queries/tree-sitter-languages/pony-tags.scm +39 -0
  36. opsmith/queries/tree-sitter-languages/properties-tags.scm +5 -0
  37. opsmith/queries/tree-sitter-languages/python-tags.scm +14 -0
  38. opsmith/queries/tree-sitter-languages/ql-tags.scm +26 -0
  39. opsmith/queries/tree-sitter-languages/r-tags.scm +21 -0
  40. opsmith/queries/tree-sitter-languages/racket-tags.scm +12 -0
  41. opsmith/queries/tree-sitter-languages/ruby-tags.scm +64 -0
  42. opsmith/queries/tree-sitter-languages/rust-tags.scm +60 -0
  43. opsmith/queries/tree-sitter-languages/scala-tags.scm +65 -0
  44. opsmith/queries/tree-sitter-languages/solidity-tags.scm +43 -0
  45. opsmith/queries/tree-sitter-languages/swift-tags.scm +51 -0
  46. opsmith/queries/tree-sitter-languages/typescript-tags.scm +41 -0
  47. opsmith/queries/tree-sitter-languages/udev-tags.scm +20 -0
  48. opsmith/repo_map.py +572 -0
  49. opsmith/settings.py +26 -0
  50. opsmith/spinner.py +221 -0
  51. opsmith_cli-0.1.2a0.dist-info/METADATA +31 -0
  52. opsmith_cli-0.1.2a0.dist-info/RECORD +55 -0
  53. opsmith_cli-0.1.2a0.dist-info/WHEEL +4 -0
  54. opsmith_cli-0.1.2a0.dist-info/entry_points.txt +2 -0
  55. opsmith_cli-0.1.2a0.dist-info/licenses/LICENSE.txt +674 -0
opsmith/__init__.py ADDED
File without changes
opsmith/agent.py ADDED
@@ -0,0 +1,243 @@
1
+ import json
2
+ import os
3
+ import shutil
4
+ import subprocess
5
+ import tempfile
6
+ import uuid # Added for unique naming
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import List, Literal
10
+
11
+ from pydantic import BaseModel
12
+ from pydantic_ai import Agent, ModelRetry, RunContext
13
+
14
+
15
+ class ModelConfig(BaseModel):
16
+ provider: Literal["openai", "anthropic", "google-gla"]
17
+ model: str
18
+ api_key_prefix: str
19
+
20
+ @property
21
+ def model_name_abs(self):
22
+ return f"{self.provider}:{self.model}"
23
+
24
+ @property
25
+ def api_key_env_var(self):
26
+ return f"{self.api_key_prefix}_API_KEY"
27
+
28
+ def ensure_auth(self, api_key: str):
29
+ os.environ[self.api_key_env_var] = api_key.strip()
30
+
31
+
32
+ AVAILABLE_MODELS = [
33
+ ModelConfig(provider="openai", model="gpt-4.1", api_key_prefix="OPENAI"),
34
+ ModelConfig(
35
+ provider="anthropic", model="claude-3-7-sonnet-20250219", api_key_prefix="ANTHROPIC"
36
+ ),
37
+ ModelConfig(provider="anthropic", model="claude-sonnet-4-20250514", api_key_prefix="ANTHROPIC"),
38
+ ModelConfig(
39
+ provider="google-gla", model="gemini-2.5-pro-preview-05-06", api_key_prefix="GEMINI"
40
+ ),
41
+ ModelConfig(
42
+ provider="google-gla", model="gemini-2.5-pro-preview-06-05", api_key_prefix="GEMINI"
43
+ ),
44
+ ]
45
+
46
+ AVAILABLE_MODELS_XREF = {model.model_name_abs: model for model in AVAILABLE_MODELS}
47
+
48
+
49
+ @dataclass
50
+ class AgentDeps:
51
+ src_dir: Path
52
+
53
+
54
+ def is_duplicate_tool_call(ctx: RunContext[AgentDeps], tool_name: str) -> bool:
55
+ """"""
56
+ tool_calls = set()
57
+ message_parts = [item for message in ctx.messages for item in message.parts]
58
+ for part in message_parts:
59
+ if part.part_kind == "tool-call" and part.tool_name == tool_name:
60
+ if isinstance(part.args, dict):
61
+ tool_args = json.dumps(part.args, sort_keys=True)
62
+ else:
63
+ tool_args = part.args
64
+ if tool_args in tool_calls:
65
+ return True
66
+ else:
67
+ # logger.debug(f"Tool {tool_def.name} called with arguments: {tool_args}")
68
+ tool_calls.add(tool_args)
69
+
70
+ return False
71
+
72
+
73
+ def build_agent(model_config: ModelConfig, instrument: bool = False) -> Agent:
74
+ agent = Agent(
75
+ model=model_config.model_name_abs,
76
+ # instructions=SYSTEM_PROMPT,
77
+ instrument=instrument,
78
+ deps_type=AgentDeps,
79
+ )
80
+
81
+ @agent.tool(retries=5)
82
+ def read_file_content(ctx: RunContext[AgentDeps], filenames: List[str]) -> List[str]:
83
+ """
84
+ Reads and returns the content of specified files from the repository.
85
+ Use this to understand file structures, dependencies, or specific configurations.
86
+ Provide the relative file paths from the repository root.
87
+
88
+ Args:
89
+ ctx: The run context object containing the dependencies of the agent.
90
+ filenames: A list of relative paths to the files from the repository root.
91
+
92
+ Returns:
93
+ A list of strings, where each string is the content of the corresponding file.
94
+ The order of contents in the list matches the order of filenames in the input.
95
+ """
96
+ if is_duplicate_tool_call(ctx, "read_file_content"):
97
+ raise ModelRetry(
98
+ "The tool 'read_file_content' has already been called with the exact same list of "
99
+ "files in this conversation."
100
+ )
101
+
102
+ contents = []
103
+ for filename in filenames:
104
+ if Path(filename).is_absolute():
105
+ raise ModelRetry(
106
+ f"Absolute file paths are not allowed for '{filename}'. Please provide a"
107
+ " relative path."
108
+ )
109
+
110
+ absolute_file_path = ctx.deps.src_dir.joinpath(filename).resolve()
111
+
112
+ if not str(absolute_file_path).startswith(str(ctx.deps.src_dir)):
113
+ raise ModelRetry(
114
+ f"Access denied. File '{filename}' is outside the repository root."
115
+ )
116
+
117
+ if not absolute_file_path.is_file():
118
+ raise ModelRetry(f"File '{filename}' not found or is not a regular file.")
119
+
120
+ with open(absolute_file_path, "r", encoding="utf-8", errors="ignore") as f:
121
+ content = f.read()
122
+ contents.append(content)
123
+ return contents
124
+
125
+ @agent.tool(retries=3)
126
+ def build_dockerfile(
127
+ ctx: RunContext[AgentDeps],
128
+ dockerfile_content: str,
129
+ ) -> str:
130
+ """
131
+ Writes the provided Dockerfile content to a temporary file, then attempts to build a Docker image
132
+ using that Dockerfile and the repository root as the build context.
133
+ If the build is successful, it attempts to run the built image with a short timeout.
134
+ Returns the combined output (stdout and stderr) of the 'docker build' and 'docker run' commands.
135
+
136
+ Use this tool to validate a generated Dockerfile.
137
+ - If the build fails, analyze the build output, revise the Dockerfile content, and call this tool again.
138
+ - If the build succeeds but the image run fails due to issues like missing packages or invalid commands
139
+ (ignoring errors related to missing environment variables or connection issues),
140
+ analyze the run output, revise the Dockerfile, and call this tool again.
141
+
142
+ Args:
143
+ ctx: The run context object.
144
+ dockerfile_content: The string content of the Dockerfile to be built and run.
145
+
146
+ Returns:
147
+ A string containing the combined stdout and stderr from the 'docker build'
148
+ and 'docker run' commands. If 'docker' command is not found, an error message is returned.
149
+ """
150
+ repo_root = ctx.deps.src_dir.resolve()
151
+ image_tag = f"opsmith-build-test-{uuid.uuid4()}"
152
+ build_output_str = ""
153
+
154
+ # Check if docker command is available
155
+ if not shutil.which("docker"):
156
+ raise ModelRetry(
157
+ "Error: Docker command not found. Please ensure Docker is installed and in your"
158
+ " PATH."
159
+ )
160
+
161
+ try:
162
+ # Create temporary directory for Dockerfile
163
+ with tempfile.TemporaryDirectory() as temp_dir:
164
+ temp_dockerfile = Path(temp_dir) / "Dockerfile"
165
+ # Write Dockerfile content
166
+ with open(temp_dockerfile, "w", encoding="utf-8") as f:
167
+ f.write(dockerfile_content)
168
+
169
+ # Execute docker build command
170
+ build_process = subprocess.run(
171
+ [
172
+ "docker",
173
+ "build",
174
+ "-f",
175
+ str(temp_dockerfile),
176
+ "-t",
177
+ image_tag,
178
+ str(repo_root),
179
+ ],
180
+ capture_output=True,
181
+ text=True,
182
+ )
183
+ build_output_str = (
184
+ f"Build Output (stdout):\n{build_process.stdout}\nBuild Output"
185
+ f" (stderr):\n{build_process.stderr}"
186
+ )
187
+
188
+ if build_process.returncode != 0:
189
+ # Build failed, instruct LLM to retry with build output
190
+ raise ModelRetry(
191
+ "Dockerfile build failed. Analyze the following output and revise the"
192
+ f" Dockerfile:\n{build_output_str}"
193
+ )
194
+
195
+ # Build successful, now try to run the image
196
+ # Using --rm to automatically remove the container when it exits.
197
+ run_process = subprocess.run(
198
+ [
199
+ "docker",
200
+ "run",
201
+ "--rm",
202
+ image_tag,
203
+ ], # Removed explicit container name as --rm handles it
204
+ capture_output=True,
205
+ text=True,
206
+ timeout=30, # Timeout for the run command to prevent indefinite hangs
207
+ )
208
+ run_output_str = (
209
+ f"Run Output (stdout):\n{run_process.stdout}\nRun Output"
210
+ f" (stderr):\n{run_process.stderr}"
211
+ )
212
+
213
+ if run_process.returncode != 0:
214
+ # Run failed. Raise ModelRetry with the run output for the LLM to analyze.
215
+ # The LLM will decide if the error is due to the Dockerfile or an ignorable runtime issue.
216
+ raise ModelRetry(
217
+ "Dockerfile built successfully, but running the image failed. Analyze the"
218
+ " following run output to determine if the Dockerfile needs revision (e.g.,"
219
+ " for missing packages, command errors) or if the error is ignorable (e.g.,"
220
+ " missing environment variables, connection issues).\n\nRun"
221
+ f" Output:\n{run_output_str}\n\nOriginal Build Output was:\n{build_output_str}"
222
+ )
223
+ finally:
224
+ # Clean up image
225
+ if image_tag: # ensure image_tag was set before trying to remove
226
+ cleanup_image_process = subprocess.run(
227
+ ["docker", "rmi", "-f", image_tag], capture_output=True, text=True
228
+ )
229
+ if (
230
+ cleanup_image_process.returncode != 0
231
+ and "no such image" not in cleanup_image_process.stderr.lower()
232
+ ):
233
+ # Log or handle image removal failure if necessary, but don't fail the tool for this
234
+ # This could happen if the build failed before the image was tagged,
235
+ # or if another process removed it.
236
+ print(
237
+ f"Warning: Failed to remove Docker image {image_tag}:"
238
+ f" {cleanup_image_process.stderr.strip()}"
239
+ )
240
+
241
+ return f"{build_output_str}\n\n{run_output_str}".strip()
242
+
243
+ return agent
@@ -0,0 +1,10 @@
1
+ from typing import Dict, Type
2
+
3
+ from .aws import AWSProvider
4
+ from .base import BaseCloudProvider, CloudProviderEnum
5
+ from .gcp import GCPProvider
6
+
7
+ CLOUD_PROVIDER_REGISTRY: Dict[CloudProviderEnum, Type[BaseCloudProvider]] = {
8
+ CloudProviderEnum.AWS: AWSProvider,
9
+ CloudProviderEnum.GCP: GCPProvider,
10
+ }
@@ -0,0 +1,46 @@
1
+ import boto3
2
+ from botocore.exceptions import ClientError, NoCredentialsError
3
+
4
+ from opsmith.cloud_providers.base import (
5
+ AWSCloudDetail,
6
+ BaseCloudProvider,
7
+ CloudCredentialsError,
8
+ CloudProviderEnum,
9
+ )
10
+
11
+
12
+ class AWSProvider(BaseCloudProvider):
13
+ """AWS cloud provider implementation."""
14
+
15
+ def get_account_details(self) -> AWSCloudDetail:
16
+ """
17
+ Retrieves structured AWS account details.
18
+ """
19
+ try:
20
+ sts_client = boto3.client("sts")
21
+ identity = sts_client.get_caller_identity()
22
+ account_id = identity.get("Account")
23
+ if not account_id:
24
+ raise CloudCredentialsError(
25
+ message=(
26
+ "AWS account ID could not be determined. This might indicate an issue with"
27
+ " the credentials or permissions."
28
+ ),
29
+ help_url="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html",
30
+ )
31
+ return AWSCloudDetail(name=CloudProviderEnum.AWS.name, account_id=account_id)
32
+ except (NoCredentialsError, ClientError) as e:
33
+ raise CloudCredentialsError(
34
+ message=f"AWS credentials error: {e}",
35
+ help_url=(
36
+ "https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html"
37
+ ),
38
+ )
39
+ except Exception as e:
40
+ # Catching other unexpected exceptions during AWS interaction
41
+ raise CloudCredentialsError(
42
+ message=f"An unexpected error occurred while fetching AWS account details: {e}",
43
+ help_url=(
44
+ "https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html"
45
+ ),
46
+ )
@@ -0,0 +1,57 @@
1
+ import abc
2
+ import enum
3
+ from typing import Literal, Union
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+
8
+ class CloudProviderEnum(enum.Enum):
9
+ AWS = "AWS"
10
+ GCP = "GCP"
11
+
12
+
13
+ class AWSCloudDetail(BaseModel):
14
+ name: Literal[CloudProviderEnum.AWS.name] = Field(
15
+ default=CloudProviderEnum.AWS.name, description="Provider name, 'aws'"
16
+ )
17
+ account_id: str = Field(..., description="AWS Account ID.")
18
+
19
+
20
+ class GCPCloudDetail(BaseModel):
21
+ name: Literal[CloudProviderEnum.GCP.name] = Field(
22
+ default=CloudProviderEnum.GCP.name, description="Provider name, 'gcp'"
23
+ )
24
+ project_id: str = Field(..., description="GCP Project ID.")
25
+
26
+
27
+ CloudProviderDetail = Union[AWSCloudDetail, GCPCloudDetail]
28
+
29
+
30
+ class CloudCredentialsError(Exception):
31
+ """Custom exception for cloud credential errors."""
32
+
33
+ def __init__(self, message: str, help_url: str):
34
+ self.message = message
35
+ self.help_url = help_url
36
+ super().__init__(
37
+ f"{self.message}\nPlease ensure your credentials are set up correctly. For more"
38
+ f" information, visit: {self.help_url}"
39
+ )
40
+
41
+
42
+ class BaseCloudProvider(abc.ABC):
43
+ """Abstract base class for cloud providers."""
44
+
45
+ def __init__(self, *args, **kwargs):
46
+ """
47
+ Initializes the cloud provider.
48
+ Subclasses should implement specific authentication and setup.
49
+ """
50
+ pass
51
+
52
+ @abc.abstractmethod
53
+ def get_account_details(self) -> CloudProviderDetail:
54
+ """
55
+ Retrieves structured account details for the cloud provider.
56
+ """
57
+ raise NotImplementedError
@@ -0,0 +1,67 @@
1
+ import google.auth
2
+ import inquirer
3
+ from google.auth.credentials import Credentials
4
+ from google.auth.exceptions import DefaultCredentialsError
5
+
6
+ from opsmith.cloud_providers import CloudProviderEnum
7
+ from opsmith.cloud_providers.base import (
8
+ BaseCloudProvider,
9
+ CloudCredentialsError,
10
+ GCPCloudDetail,
11
+ )
12
+
13
+
14
+ class GCPProvider(BaseCloudProvider):
15
+ """GCP cloud provider implementation."""
16
+
17
+ def __init__(self, *args, **kwargs):
18
+ super().__init__(*args, **kwargs)
19
+ self._credentials = None
20
+
21
+ def get_credentials(self) -> Credentials:
22
+ """
23
+ Provides the functionality to retrieve cached credentials or obtain default
24
+ Google credentials if none are available.
25
+
26
+ :raises google.auth.exceptions.GoogleAuthError: If authentication fails or
27
+ valid credentials could not be obtained.
28
+ :rtype: google.auth.credentials.Credentials
29
+ :return: Returns the cached credentials if available, otherwise retrieves
30
+ and returns the default credentials via Google's authentication library.
31
+ """
32
+ if not self._credentials:
33
+ self._credentials, _ = google.auth.default()
34
+ return self._credentials
35
+
36
+ def get_account_details(self) -> GCPCloudDetail:
37
+ """
38
+ Retrieves structured GCP account details by listing available projects
39
+ and prompting the user for selection.
40
+ """
41
+ try:
42
+ self.get_credentials()
43
+
44
+ questions = [
45
+ inquirer.Text(
46
+ name="project_id",
47
+ message="Enter the GCP project you want to use",
48
+ ),
49
+ ]
50
+
51
+ answers = inquirer.prompt(questions)
52
+ if not answers or not answers.get("project_id"):
53
+ raise ValueError("GCP project selection is required. Aborting.")
54
+
55
+ selected_project_id = answers["project_id"]
56
+ return GCPCloudDetail(name=CloudProviderEnum.GCP.name, project_id=selected_project_id)
57
+
58
+ except DefaultCredentialsError as e:
59
+ raise CloudCredentialsError(
60
+ message=f"GCP Application Default Credentials error: {e}",
61
+ help_url="https://cloud.google.com/docs/authentication/provide-credentials-adc",
62
+ )
63
+ except Exception as e:
64
+ raise CloudCredentialsError(
65
+ message=f"An unexpected error occurred while fetching GCP project list: {e}",
66
+ help_url="https://cloud.google.com/docs/authentication/provide-credentials-adc",
67
+ )
opsmith/constants.py ADDED
@@ -0,0 +1,175 @@
1
+ ROOT_IMPORTANT_FILES = [
2
+ # Version Control
3
+ ".gitignore",
4
+ ".gitattributes",
5
+ # Documentation
6
+ "README",
7
+ "README.md",
8
+ "README.txt",
9
+ "README.rst",
10
+ "CONTRIBUTING",
11
+ "CONTRIBUTING.md",
12
+ "CONTRIBUTING.txt",
13
+ "CONTRIBUTING.rst",
14
+ "LICENSE",
15
+ "LICENSE.md",
16
+ "LICENSE.txt",
17
+ "CHANGELOG",
18
+ "CHANGELOG.md",
19
+ "CHANGELOG.txt",
20
+ "CHANGELOG.rst",
21
+ "SECURITY",
22
+ "SECURITY.md",
23
+ "SECURITY.txt",
24
+ "CODEOWNERS",
25
+ # Package Management and Dependencies
26
+ "requirements.txt",
27
+ "Pipfile",
28
+ "Pipfile.lock",
29
+ "pyproject.toml",
30
+ "setup.py",
31
+ "setup.cfg",
32
+ "package.json",
33
+ "package-lock.json",
34
+ "yarn.lock",
35
+ "npm-shrinkwrap.json",
36
+ "Gemfile",
37
+ "Gemfile.lock",
38
+ "composer.json",
39
+ "composer.lock",
40
+ "pom.xml",
41
+ "build.gradle",
42
+ "build.gradle.kts",
43
+ "build.sbt",
44
+ "go.mod",
45
+ "go.sum",
46
+ "Cargo.toml",
47
+ "Cargo.lock",
48
+ "mix.exs",
49
+ "rebar.config",
50
+ "project.clj",
51
+ "Podfile",
52
+ "Cartfile",
53
+ "dub.json",
54
+ "dub.sdl",
55
+ # Configuration and Settings
56
+ ".env",
57
+ ".env.example",
58
+ ".editorconfig",
59
+ "tsconfig.json",
60
+ "jsconfig.json",
61
+ ".babelrc",
62
+ "babel.config.js",
63
+ ".eslintrc",
64
+ ".eslintignore",
65
+ ".prettierrc",
66
+ ".stylelintrc",
67
+ "tslint.json",
68
+ ".pylintrc",
69
+ ".flake8",
70
+ ".rubocop.yml",
71
+ ".scalafmt.conf",
72
+ ".dockerignore",
73
+ ".gitpod.yml",
74
+ "sonar-project.properties",
75
+ "renovate.json",
76
+ "dependabot.yml",
77
+ ".pre-commit-config.yaml",
78
+ "mypy.ini",
79
+ "tox.ini",
80
+ ".yamllint",
81
+ "pyrightconfig.json",
82
+ # Build and Compilation
83
+ "webpack.config.js",
84
+ "rollup.config.js",
85
+ "parcel.config.js",
86
+ "gulpfile.js",
87
+ "Gruntfile.js",
88
+ "build.xml",
89
+ "build.boot",
90
+ "project.json",
91
+ "build.cake",
92
+ "MANIFEST.in",
93
+ # Testing
94
+ "pytest.ini",
95
+ "phpunit.xml",
96
+ "karma.conf.js",
97
+ "jest.config.js",
98
+ "cypress.json",
99
+ ".nycrc",
100
+ ".nycrc.json",
101
+ # CI/CD
102
+ ".travis.yml",
103
+ ".gitlab-ci.yml",
104
+ "Jenkinsfile",
105
+ "azure-pipelines.yml",
106
+ "bitbucket-pipelines.yml",
107
+ "appveyor.yml",
108
+ "circle.yml",
109
+ ".circleci/config.yml",
110
+ ".github/dependabot.yml",
111
+ "codecov.yml",
112
+ ".coveragerc",
113
+ # Docker and Containers
114
+ "Dockerfile",
115
+ "docker-compose.yml",
116
+ "docker-compose.override.yml",
117
+ # Cloud and Serverless
118
+ "serverless.yml",
119
+ "firebase.json",
120
+ "now.json",
121
+ "netlify.toml",
122
+ "vercel.json",
123
+ "app.yaml",
124
+ "terraform.tf",
125
+ "main.tf",
126
+ "cloudformation.yaml",
127
+ "cloudformation.json",
128
+ "ansible.cfg",
129
+ "kubernetes.yaml",
130
+ "k8s.yaml",
131
+ # Database
132
+ "schema.sql",
133
+ "liquibase.properties",
134
+ "flyway.conf",
135
+ # Framework-specific
136
+ "next.config.js",
137
+ "nuxt.config.js",
138
+ "vue.config.js",
139
+ "angular.json",
140
+ "gatsby-config.js",
141
+ "gridsome.config.js",
142
+ # API Documentation
143
+ "swagger.yaml",
144
+ "swagger.json",
145
+ "openapi.yaml",
146
+ "openapi.json",
147
+ # Development environment
148
+ ".nvmrc",
149
+ ".ruby-version",
150
+ ".python-version",
151
+ "Vagrantfile",
152
+ # Quality and metrics
153
+ ".codeclimate.yml",
154
+ "codecov.yml",
155
+ # Documentation
156
+ "mkdocs.yml",
157
+ "_config.yml",
158
+ "book.toml",
159
+ "readthedocs.yml",
160
+ ".readthedocs.yaml",
161
+ # Package registries
162
+ ".npmrc",
163
+ ".yarnrc",
164
+ # Linting and formatting
165
+ ".isort.cfg",
166
+ ".markdownlint.json",
167
+ ".markdownlint.yaml",
168
+ # Security
169
+ ".bandit",
170
+ ".secrets.baseline",
171
+ # Misc
172
+ ".pypirc",
173
+ ".gitkeep",
174
+ ".npmignore",
175
+ ]