shotgun-sh 0.2.29.dev2__py3-none-any.whl → 0.6.1.dev1__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 shotgun-sh might be problematic. Click here for more details.

Files changed (161) hide show
  1. shotgun/agents/agent_manager.py +497 -30
  2. shotgun/agents/cancellation.py +103 -0
  3. shotgun/agents/common.py +90 -77
  4. shotgun/agents/config/README.md +0 -1
  5. shotgun/agents/config/manager.py +52 -8
  6. shotgun/agents/config/models.py +48 -45
  7. shotgun/agents/config/provider.py +44 -29
  8. shotgun/agents/conversation/history/file_content_deduplication.py +66 -43
  9. shotgun/agents/conversation/history/token_counting/base.py +51 -9
  10. shotgun/agents/export.py +12 -13
  11. shotgun/agents/file_read.py +176 -0
  12. shotgun/agents/messages.py +15 -3
  13. shotgun/agents/models.py +90 -2
  14. shotgun/agents/plan.py +12 -13
  15. shotgun/agents/research.py +13 -10
  16. shotgun/agents/router/__init__.py +47 -0
  17. shotgun/agents/router/models.py +384 -0
  18. shotgun/agents/router/router.py +185 -0
  19. shotgun/agents/router/tools/__init__.py +18 -0
  20. shotgun/agents/router/tools/delegation_tools.py +557 -0
  21. shotgun/agents/router/tools/plan_tools.py +403 -0
  22. shotgun/agents/runner.py +17 -2
  23. shotgun/agents/specify.py +12 -13
  24. shotgun/agents/tasks.py +12 -13
  25. shotgun/agents/tools/__init__.py +8 -0
  26. shotgun/agents/tools/codebase/directory_lister.py +27 -39
  27. shotgun/agents/tools/codebase/file_read.py +26 -35
  28. shotgun/agents/tools/codebase/query_graph.py +9 -0
  29. shotgun/agents/tools/codebase/retrieve_code.py +9 -0
  30. shotgun/agents/tools/file_management.py +81 -3
  31. shotgun/agents/tools/file_read_tools/__init__.py +7 -0
  32. shotgun/agents/tools/file_read_tools/multimodal_file_read.py +167 -0
  33. shotgun/agents/tools/markdown_tools/__init__.py +62 -0
  34. shotgun/agents/tools/markdown_tools/insert_section.py +148 -0
  35. shotgun/agents/tools/markdown_tools/models.py +86 -0
  36. shotgun/agents/tools/markdown_tools/remove_section.py +114 -0
  37. shotgun/agents/tools/markdown_tools/replace_section.py +119 -0
  38. shotgun/agents/tools/markdown_tools/utils.py +453 -0
  39. shotgun/agents/tools/registry.py +41 -0
  40. shotgun/agents/tools/web_search/__init__.py +1 -2
  41. shotgun/agents/tools/web_search/gemini.py +1 -3
  42. shotgun/agents/tools/web_search/openai.py +42 -23
  43. shotgun/attachments/__init__.py +41 -0
  44. shotgun/attachments/errors.py +60 -0
  45. shotgun/attachments/models.py +107 -0
  46. shotgun/attachments/parser.py +257 -0
  47. shotgun/attachments/processor.py +193 -0
  48. shotgun/cli/clear.py +2 -2
  49. shotgun/cli/codebase/commands.py +181 -65
  50. shotgun/cli/compact.py +2 -2
  51. shotgun/cli/context.py +2 -2
  52. shotgun/cli/run.py +90 -0
  53. shotgun/cli/spec/backup.py +2 -1
  54. shotgun/cli/spec/commands.py +2 -0
  55. shotgun/cli/spec/models.py +18 -0
  56. shotgun/cli/spec/pull_service.py +122 -68
  57. shotgun/codebase/__init__.py +2 -0
  58. shotgun/codebase/benchmarks/__init__.py +35 -0
  59. shotgun/codebase/benchmarks/benchmark_runner.py +309 -0
  60. shotgun/codebase/benchmarks/exporters.py +119 -0
  61. shotgun/codebase/benchmarks/formatters/__init__.py +49 -0
  62. shotgun/codebase/benchmarks/formatters/base.py +34 -0
  63. shotgun/codebase/benchmarks/formatters/json_formatter.py +106 -0
  64. shotgun/codebase/benchmarks/formatters/markdown.py +136 -0
  65. shotgun/codebase/benchmarks/models.py +129 -0
  66. shotgun/codebase/core/__init__.py +4 -0
  67. shotgun/codebase/core/call_resolution.py +91 -0
  68. shotgun/codebase/core/change_detector.py +11 -6
  69. shotgun/codebase/core/errors.py +159 -0
  70. shotgun/codebase/core/extractors/__init__.py +23 -0
  71. shotgun/codebase/core/extractors/base.py +138 -0
  72. shotgun/codebase/core/extractors/factory.py +63 -0
  73. shotgun/codebase/core/extractors/go/__init__.py +7 -0
  74. shotgun/codebase/core/extractors/go/extractor.py +122 -0
  75. shotgun/codebase/core/extractors/javascript/__init__.py +7 -0
  76. shotgun/codebase/core/extractors/javascript/extractor.py +132 -0
  77. shotgun/codebase/core/extractors/protocol.py +109 -0
  78. shotgun/codebase/core/extractors/python/__init__.py +7 -0
  79. shotgun/codebase/core/extractors/python/extractor.py +141 -0
  80. shotgun/codebase/core/extractors/rust/__init__.py +7 -0
  81. shotgun/codebase/core/extractors/rust/extractor.py +139 -0
  82. shotgun/codebase/core/extractors/types.py +15 -0
  83. shotgun/codebase/core/extractors/typescript/__init__.py +7 -0
  84. shotgun/codebase/core/extractors/typescript/extractor.py +92 -0
  85. shotgun/codebase/core/gitignore.py +252 -0
  86. shotgun/codebase/core/ingestor.py +644 -354
  87. shotgun/codebase/core/kuzu_compat.py +119 -0
  88. shotgun/codebase/core/language_config.py +239 -0
  89. shotgun/codebase/core/manager.py +256 -46
  90. shotgun/codebase/core/metrics_collector.py +310 -0
  91. shotgun/codebase/core/metrics_types.py +347 -0
  92. shotgun/codebase/core/parallel_executor.py +424 -0
  93. shotgun/codebase/core/work_distributor.py +254 -0
  94. shotgun/codebase/core/worker.py +768 -0
  95. shotgun/codebase/indexing_state.py +86 -0
  96. shotgun/codebase/models.py +94 -0
  97. shotgun/codebase/service.py +13 -0
  98. shotgun/exceptions.py +1 -1
  99. shotgun/main.py +2 -10
  100. shotgun/prompts/agents/export.j2 +2 -0
  101. shotgun/prompts/agents/file_read.j2 +48 -0
  102. shotgun/prompts/agents/partials/common_agent_system_prompt.j2 +20 -28
  103. shotgun/prompts/agents/partials/content_formatting.j2 +12 -33
  104. shotgun/prompts/agents/partials/interactive_mode.j2 +9 -32
  105. shotgun/prompts/agents/partials/router_delegation_mode.j2 +35 -0
  106. shotgun/prompts/agents/plan.j2 +43 -1
  107. shotgun/prompts/agents/research.j2 +75 -20
  108. shotgun/prompts/agents/router.j2 +713 -0
  109. shotgun/prompts/agents/specify.j2 +94 -4
  110. shotgun/prompts/agents/state/codebase/codebase_graphs_available.j2 +14 -1
  111. shotgun/prompts/agents/state/system_state.j2 +24 -15
  112. shotgun/prompts/agents/tasks.j2 +77 -23
  113. shotgun/settings.py +44 -0
  114. shotgun/shotgun_web/shared_specs/upload_pipeline.py +38 -0
  115. shotgun/tui/app.py +90 -23
  116. shotgun/tui/commands/__init__.py +9 -1
  117. shotgun/tui/components/attachment_bar.py +87 -0
  118. shotgun/tui/components/mode_indicator.py +120 -25
  119. shotgun/tui/components/prompt_input.py +23 -28
  120. shotgun/tui/components/status_bar.py +5 -4
  121. shotgun/tui/dependencies.py +58 -8
  122. shotgun/tui/protocols.py +37 -0
  123. shotgun/tui/screens/chat/chat.tcss +24 -1
  124. shotgun/tui/screens/chat/chat_screen.py +1374 -211
  125. shotgun/tui/screens/chat/codebase_index_prompt_screen.py +8 -4
  126. shotgun/tui/screens/chat_screen/attachment_hint.py +40 -0
  127. shotgun/tui/screens/chat_screen/command_providers.py +0 -97
  128. shotgun/tui/screens/chat_screen/history/agent_response.py +7 -3
  129. shotgun/tui/screens/chat_screen/history/chat_history.py +49 -6
  130. shotgun/tui/screens/chat_screen/history/formatters.py +75 -15
  131. shotgun/tui/screens/chat_screen/history/partial_response.py +11 -1
  132. shotgun/tui/screens/chat_screen/history/user_question.py +25 -3
  133. shotgun/tui/screens/chat_screen/messages.py +219 -0
  134. shotgun/tui/screens/database_locked_dialog.py +219 -0
  135. shotgun/tui/screens/database_timeout_dialog.py +158 -0
  136. shotgun/tui/screens/kuzu_error_dialog.py +135 -0
  137. shotgun/tui/screens/model_picker.py +14 -9
  138. shotgun/tui/screens/models.py +11 -0
  139. shotgun/tui/screens/shotgun_auth.py +50 -0
  140. shotgun/tui/screens/spec_pull.py +2 -0
  141. shotgun/tui/state/processing_state.py +19 -0
  142. shotgun/tui/utils/mode_progress.py +20 -86
  143. shotgun/tui/widgets/__init__.py +2 -1
  144. shotgun/tui/widgets/approval_widget.py +152 -0
  145. shotgun/tui/widgets/cascade_confirmation_widget.py +203 -0
  146. shotgun/tui/widgets/plan_panel.py +129 -0
  147. shotgun/tui/widgets/step_checkpoint_widget.py +180 -0
  148. shotgun/tui/widgets/widget_coordinator.py +18 -0
  149. shotgun/utils/file_system_utils.py +4 -1
  150. {shotgun_sh-0.2.29.dev2.dist-info → shotgun_sh-0.6.1.dev1.dist-info}/METADATA +88 -34
  151. shotgun_sh-0.6.1.dev1.dist-info/RECORD +292 -0
  152. shotgun/cli/export.py +0 -81
  153. shotgun/cli/plan.py +0 -73
  154. shotgun/cli/research.py +0 -93
  155. shotgun/cli/specify.py +0 -70
  156. shotgun/cli/tasks.py +0 -78
  157. shotgun/tui/screens/onboarding.py +0 -580
  158. shotgun_sh-0.2.29.dev2.dist-info/RECORD +0 -229
  159. {shotgun_sh-0.2.29.dev2.dist-info → shotgun_sh-0.6.1.dev1.dist-info}/WHEEL +0 -0
  160. {shotgun_sh-0.2.29.dev2.dist-info → shotgun_sh-0.6.1.dev1.dist-info}/entry_points.txt +0 -0
  161. {shotgun_sh-0.2.29.dev2.dist-info → shotgun_sh-0.6.1.dev1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,119 @@
1
+ """Lazy import wrapper for kuzu (real_ladybug) with Windows compatibility handling."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ import webbrowser
7
+ from typing import Any
8
+
9
+ _kuzu_module: Any = None
10
+ _import_error: ImportError | None = None
11
+
12
+ # Windows VC++ download URL
13
+ _VC_REDIST_URL = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
14
+
15
+ # PowerShell installation script for VC++ Redistributable
16
+ _VC_INSTALL_SCRIPT = f"""\
17
+ # Download and install Visual C++ Redistributable (run as Administrator)
18
+ Import-Module BitsTransfer
19
+ Start-BitsTransfer -Source "{_VC_REDIST_URL}" -Destination "$env:TEMP\\vc_redist.x64.exe"
20
+ Start-Process -FilePath "$env:TEMP\\vc_redist.x64.exe" -ArgumentList "/install", "/quiet", "/norestart" -Wait\
21
+ """
22
+
23
+ # Windows VC++ installation instructions
24
+ _WINDOWS_INSTALL_INSTRUCTIONS = f"""
25
+ To fix this, install the Visual C++ Redistributable.
26
+
27
+ Option 1: Run this PowerShell script (as Administrator):
28
+
29
+ {_VC_INSTALL_SCRIPT}
30
+
31
+ Option 2: Download manually from:
32
+ {_VC_REDIST_URL}
33
+ """
34
+
35
+
36
+ def copy_vcpp_script_to_clipboard() -> bool:
37
+ """Copy the VC++ installation PowerShell script to clipboard.
38
+
39
+ Returns:
40
+ True if successful, False otherwise
41
+ """
42
+ try:
43
+ import pyperclip # type: ignore[import-untyped]
44
+
45
+ pyperclip.copy(_VC_INSTALL_SCRIPT)
46
+ return True
47
+ except Exception:
48
+ return False
49
+
50
+
51
+ def open_vcpp_download_page() -> bool:
52
+ """Open the VC++ Redistributable download page in the default browser.
53
+
54
+ Returns:
55
+ True if successful, False otherwise
56
+ """
57
+ try:
58
+ webbrowser.open(_VC_REDIST_URL)
59
+ return True
60
+ except Exception:
61
+ return False
62
+
63
+
64
+ class KuzuImportError(ImportError):
65
+ """Raised when kuzu cannot be imported, typically on Windows due to DLL issues."""
66
+
67
+ def __init__(self, original_error: ImportError) -> None:
68
+ self.original_error = original_error
69
+ if sys.platform == "win32":
70
+ message = (
71
+ "Failed to load the graph database library (real_ladybug).\n\n"
72
+ "This error typically occurs on Windows when the Visual C++ "
73
+ "Redistributable is not installed.\n"
74
+ f"{_WINDOWS_INSTALL_INSTRUCTIONS}\n"
75
+ f"Original error: {original_error}"
76
+ )
77
+ else:
78
+ message = f"Failed to import real_ladybug: {original_error}"
79
+ super().__init__(message)
80
+
81
+
82
+ def get_kuzu() -> Any:
83
+ """Get the kuzu module, importing it lazily on first use.
84
+
85
+ Raises:
86
+ KuzuImportError: If kuzu cannot be imported (e.g., Windows DLL issues)
87
+
88
+ Returns:
89
+ The real_ladybug module
90
+ """
91
+ global _kuzu_module, _import_error
92
+
93
+ if _kuzu_module is not None:
94
+ return _kuzu_module
95
+
96
+ if _import_error is not None:
97
+ raise KuzuImportError(_import_error)
98
+
99
+ try:
100
+ import real_ladybug
101
+
102
+ _kuzu_module = real_ladybug
103
+ return _kuzu_module
104
+ except ImportError as e:
105
+ _import_error = e
106
+ raise KuzuImportError(e) from e
107
+
108
+
109
+ def is_kuzu_available() -> bool:
110
+ """Check if kuzu is available without raising an error.
111
+
112
+ Returns:
113
+ True if kuzu can be imported, False otherwise
114
+ """
115
+ try:
116
+ get_kuzu()
117
+ return True
118
+ except KuzuImportError:
119
+ return False
@@ -1,6 +1,152 @@
1
1
  """Language configuration for Tree-sitter parsing."""
2
2
 
3
3
  from dataclasses import dataclass, field
4
+ from pathlib import Path
5
+
6
+ # =============================================================================
7
+ # COMMON EXCLUSIONS (applied to all languages)
8
+ # =============================================================================
9
+
10
+ # Version control
11
+ VCS_DIRECTORIES = {
12
+ ".git",
13
+ ".hg",
14
+ ".svn",
15
+ }
16
+
17
+ # Editor and IDE directories
18
+ EDITOR_DIRECTORIES = {
19
+ ".idea",
20
+ ".vscode",
21
+ ".vs",
22
+ ".eclipse",
23
+ ".settings",
24
+ }
25
+
26
+ # AI assistant directories
27
+ AI_ASSISTANT_DIRECTORIES = {
28
+ ".claude",
29
+ ".cursor",
30
+ ".copilot",
31
+ }
32
+
33
+ # Generic build/output directories (language-agnostic)
34
+ GENERIC_BUILD_DIRECTORIES = {
35
+ "build",
36
+ "dist",
37
+ "out",
38
+ "tmp",
39
+ "temp",
40
+ "coverage",
41
+ }
42
+
43
+ # All common directories to ignore (union of above)
44
+ COMMON_IGNORE_DIRECTORIES = (
45
+ VCS_DIRECTORIES
46
+ | EDITOR_DIRECTORIES
47
+ | AI_ASSISTANT_DIRECTORIES
48
+ | GENERIC_BUILD_DIRECTORIES
49
+ )
50
+
51
+
52
+ # =============================================================================
53
+ # LANGUAGE-SPECIFIC EXCLUSIONS
54
+ # =============================================================================
55
+
56
+ PYTHON_IGNORE_DIRECTORIES = {
57
+ # Virtual environments
58
+ "venv",
59
+ ".venv",
60
+ "env",
61
+ ".env",
62
+ "virtualenv",
63
+ ".virtualenv",
64
+ # Package/build artifacts
65
+ "__pycache__",
66
+ ".eggs",
67
+ "*.egg-info",
68
+ ".tox",
69
+ ".nox",
70
+ # Tool caches
71
+ ".pytest_cache",
72
+ ".mypy_cache",
73
+ ".ruff_cache",
74
+ ".coverage",
75
+ ".hypothesis",
76
+ # Build outputs
77
+ "site-packages",
78
+ }
79
+
80
+ JAVASCRIPT_IGNORE_DIRECTORIES = {
81
+ # Dependencies
82
+ "node_modules",
83
+ "bower_components",
84
+ # Framework build outputs
85
+ ".next",
86
+ ".nuxt",
87
+ ".vite",
88
+ ".svelte-kit",
89
+ ".output",
90
+ # Package managers
91
+ ".yarn",
92
+ ".pnpm-store",
93
+ # Build tools
94
+ ".turbo",
95
+ ".parcel-cache",
96
+ ".cache",
97
+ # Deployment
98
+ ".vercel",
99
+ ".netlify",
100
+ ".serverless",
101
+ }
102
+
103
+ TYPESCRIPT_IGNORE_DIRECTORIES = JAVASCRIPT_IGNORE_DIRECTORIES | {
104
+ # TypeScript-specific
105
+ ".tsbuildinfo",
106
+ }
107
+
108
+ GO_IGNORE_DIRECTORIES = {
109
+ # Vendored dependencies
110
+ "vendor",
111
+ # Build output (common convention)
112
+ "bin",
113
+ }
114
+
115
+ RUST_IGNORE_DIRECTORIES = {
116
+ # Cargo build output
117
+ "target",
118
+ }
119
+
120
+ RUBY_IGNORE_DIRECTORIES = {
121
+ # Bundler
122
+ ".bundle",
123
+ "vendor/bundle",
124
+ }
125
+
126
+ JAVA_IGNORE_DIRECTORIES = {
127
+ # Gradle
128
+ ".gradle",
129
+ "gradle",
130
+ # Maven
131
+ ".m2",
132
+ "target",
133
+ # IDE
134
+ ".apt_generated",
135
+ }
136
+
137
+ CSHARP_IGNORE_DIRECTORIES = {
138
+ # Build outputs
139
+ "bin",
140
+ "obj",
141
+ # NuGet
142
+ "packages",
143
+ ".nuget",
144
+ }
145
+
146
+ PHP_IGNORE_DIRECTORIES = {
147
+ # Composer
148
+ "vendor",
149
+ }
4
150
 
5
151
 
6
152
  @dataclass
@@ -17,6 +163,7 @@ class LanguageConfig:
17
163
  import_node_types: list[str] = field(default_factory=list)
18
164
  import_from_node_types: list[str] = field(default_factory=list)
19
165
  package_indicators: list[str] = field(default_factory=list)
166
+ ignore_directories: set[str] = field(default_factory=set)
20
167
  function_query: str | None = None
21
168
  class_query: str | None = None
22
169
  call_query: str | None = None
@@ -36,6 +183,7 @@ LANGUAGE_CONFIGS = {
36
183
  import_node_types=["import_statement"],
37
184
  import_from_node_types=["import_from_statement"],
38
185
  package_indicators=["__init__.py"],
186
+ ignore_directories=PYTHON_IGNORE_DIRECTORIES,
39
187
  function_query="""
40
188
  (function_definition
41
189
  name: (identifier) @function_name
@@ -96,6 +244,7 @@ LANGUAGE_CONFIGS = {
96
244
  import_node_types=["import_statement"],
97
245
  import_from_node_types=["import_statement"],
98
246
  package_indicators=["package.json"],
247
+ ignore_directories=JAVASCRIPT_IGNORE_DIRECTORIES,
99
248
  function_query="""
100
249
  [
101
250
  (function_declaration name: (identifier) @function_name) @function
@@ -151,6 +300,7 @@ LANGUAGE_CONFIGS = {
151
300
  import_node_types=["import_statement"],
152
301
  import_from_node_types=["import_statement"],
153
302
  package_indicators=["package.json", "tsconfig.json"],
303
+ ignore_directories=TYPESCRIPT_IGNORE_DIRECTORIES,
154
304
  function_query="""
155
305
  [
156
306
  (function_declaration name: (identifier) @function_name) @function
@@ -197,6 +347,7 @@ LANGUAGE_CONFIGS = {
197
347
  import_node_types=["import_declaration"],
198
348
  import_from_node_types=["import_spec"],
199
349
  package_indicators=["go.mod", "go.sum"],
350
+ ignore_directories=GO_IGNORE_DIRECTORIES,
200
351
  function_query="""
201
352
  [
202
353
  (function_declaration
@@ -248,6 +399,7 @@ LANGUAGE_CONFIGS = {
248
399
  import_node_types=["use_declaration"],
249
400
  import_from_node_types=["use_as_clause", "use_list"],
250
401
  package_indicators=["Cargo.toml"],
402
+ ignore_directories=RUST_IGNORE_DIRECTORIES,
251
403
  function_query="""
252
404
  [
253
405
  (function_item
@@ -295,3 +447,90 @@ def get_language_config(file_extension: str) -> LanguageConfig | None:
295
447
  if file_extension in config.file_extensions:
296
448
  return config
297
449
  return None
450
+
451
+
452
+ def get_all_ignore_directories() -> set[str]:
453
+ """Get all ignore directories (common + all language-specific).
454
+
455
+ This is useful when indexing a codebase with multiple languages
456
+ or when you don't know what languages are present.
457
+ """
458
+ all_ignores = COMMON_IGNORE_DIRECTORIES.copy()
459
+ for config in LANGUAGE_CONFIGS.values():
460
+ all_ignores |= config.ignore_directories
461
+ return all_ignores
462
+
463
+
464
+ def get_ignore_directories_for_languages(languages: list[str]) -> set[str]:
465
+ """Get ignore directories for specific languages.
466
+
467
+ Args:
468
+ languages: List of language names (e.g., ["python", "typescript"])
469
+
470
+ Returns:
471
+ Common ignores + language-specific ignores for the given languages
472
+ """
473
+ ignores = COMMON_IGNORE_DIRECTORIES.copy()
474
+ for lang in languages:
475
+ if lang in LANGUAGE_CONFIGS:
476
+ ignores |= LANGUAGE_CONFIGS[lang].ignore_directories
477
+ return ignores
478
+
479
+
480
+ def should_ignore_directory(name: str, ignore_patterns: set[str] | None = None) -> bool:
481
+ """Check if a directory should be ignored.
482
+
483
+ Args:
484
+ name: Directory name (not full path)
485
+ ignore_patterns: Optional custom ignore patterns. If None, uses all patterns.
486
+
487
+ Returns:
488
+ True if directory should be ignored
489
+ """
490
+ patterns = (
491
+ ignore_patterns if ignore_patterns is not None else get_all_ignore_directories()
492
+ )
493
+
494
+ # Check explicit patterns
495
+ if name in patterns:
496
+ return True
497
+
498
+ # Check for glob patterns like "*.egg-info"
499
+ for pattern in patterns:
500
+ if pattern.startswith("*") and name.endswith(pattern[1:]):
501
+ return True
502
+
503
+ # Hidden directories (starting with .) are always ignored
504
+ if name.startswith("."):
505
+ return True
506
+
507
+ return False
508
+
509
+
510
+ def should_ignore_file(name: str) -> bool:
511
+ """Check if a file should be ignored.
512
+
513
+ Args:
514
+ name: File name (not full path)
515
+
516
+ Returns:
517
+ True if file should be ignored (hidden files starting with .)
518
+ """
519
+ return name.startswith(".")
520
+
521
+
522
+ def is_path_ignored(path: str | Path, ignore_patterns: set[str] | None = None) -> bool:
523
+ """Check if any part of a path should be ignored.
524
+
525
+ Args:
526
+ path: File or directory path (can be relative or absolute)
527
+ ignore_patterns: Optional custom ignore patterns
528
+
529
+ Returns:
530
+ True if any path component should be ignored
531
+ """
532
+ path_obj = Path(path) if isinstance(path, str) else path
533
+ for part in path_obj.parts:
534
+ if should_ignore_directory(part, ignore_patterns):
535
+ return True
536
+ return False