@@ -68,10 +68,12 @@ <h2 class="section-title" id="header-classes">Classes</h2>
6868 self.max_file_size = max_file_size
6969 self.max_tokens = int(os.getenv("PRAISONAI_MAX_TOKENS", max_tokens))
7070 self.ignore_patterns = self.get_ignore_patterns()
71+ self.include_paths = self.get_include_paths()
72+ self.included_files = []
7173
7274 def get_ignore_patterns(self):
7375 """
74- Loads ignore patterns from various sources, prioritizing them in
76+ Loads ignore patterns from various sources, prioritizing them in
7577 the following order:
7678 1. .praisonignore
7779 2. settings.yaml (under code.ignore_files)
@@ -129,6 +131,19 @@ <h2 class="section-title" id="header-classes">Classes</h2>
129131 logger.debug(f"Final ignore patterns: {modified_ignore_patterns}")
130132 return modified_ignore_patterns
131133
134+ def get_include_paths(self):
135+ include_paths = []
136+
137+ # 1. Load from .praisoninclude
138+ include_file = os.path.join(self.directory, '.praisoninclude')
139+ if os.path.exists(include_file):
140+ with open(include_file, 'r') as f:
141+ include_paths.extend(
142+ line.strip() for line in f
143+ if line.strip() and not line.startswith('#')
144+ )
145+ return include_paths
146+
132147 def should_ignore(self, file_path):
133148 """
134149 Check if a file or directory should be ignored based on patterns.
@@ -150,31 +165,65 @@ <h2 class="section-title" id="header-classes">Classes</h2>
150165 any(file_path.endswith(ext) for ext in self.relevant_extensions)
151166
152167 def gather_context(self):
153- """Gather context from relevant files, respecting ignore patterns."""
168+ """Gather context from relevant files, respecting ignore patterns and include paths ."""
154169 context = []
155170 total_files = 0
156171 processed_files = 0
157172
158- for root, dirs, files in os.walk(self.directory):
159- total_files += len(files)
160- dirs[:] = [d for d in dirs if not self.should_ignore(os.path.join(root, d))]
161- for file in files:
162- file_path = os.path.join(root, file)
163- if not self.should_ignore(file_path) and self.is_relevant_file(file_path):
173+ if not self.include_paths:
174+ # No include paths specified, process the entire directory
175+ for root, dirs, files in os.walk(self.directory):
176+ total_files += len(files)
177+ dirs[:] = [d for d in dirs if not self.should_ignore(os.path.join(root, d))]
178+ for file in files:
179+ file_path = os.path.join(root, file)
180+ if not self.should_ignore(file_path) and self.is_relevant_file(file_path):
181+ try:
182+ with open(file_path, 'r', encoding='utf-8') as f:
183+ content = f.read()
184+ context.append(f"File: {file_path}\n\n{content}\n\n{'='*50}\n")
185+ self.included_files.append(Path(file_path).relative_to(self.directory))
186+ except Exception as e:
187+ logger.error(f"Error reading {file_path}: {e}")
188+ processed_files += 1
189+ print(f"\rProcessed {processed_files}/{total_files} files", end="", flush=True)
190+ else:
191+ # Process specified include paths
192+ for include_path in self.include_paths:
193+ full_path = os.path.join(self.directory, include_path)
194+ if os.path.isdir(full_path):
195+ for root, dirs, files in os.walk(full_path):
196+ total_files += len(files)
197+ dirs[:] = [d for d in dirs if not self.should_ignore(os.path.join(root, d))]
198+ for file in files:
199+ file_path = os.path.join(root, file)
200+ if not self.should_ignore(file_path) and self.is_relevant_file(file_path):
201+ try:
202+ with open(file_path, 'r', encoding='utf-8') as f:
203+ content = f.read()
204+ context.append(f"File: {file_path}\n\n{content}\n\n{'='*50}\n")
205+ self.included_files.append(Path(file_path).relative_to(self.directory))
206+ except Exception as e:
207+ logger.error(f"Error reading {file_path}: {e}")
208+ processed_files += 1
209+ print(f"\rProcessed {processed_files}/{total_files} files", end="", flush=True)
210+ elif os.path.isfile(full_path) and self.is_relevant_file(full_path):
164211 try:
165- with open(file_path , 'r', encoding='utf-8') as f:
212+ with open(full_path , 'r', encoding='utf-8') as f:
166213 content = f.read()
167- context.append(f"File: {file_path}\n\n{content}\n\n{'='*50}\n")
214+ context.append(f"File: {full_path}\n\n{content}\n\n{'='*50}\n")
215+ self.included_files.append(Path(full_path).relative_to(self.directory))
168216 except Exception as e:
169- logger.error(f"Error reading {file_path}: {e}")
170- processed_files += 1
171- print(f"\rProcessed {processed_files}/{total_files} files", end="", flush=True)
217+ logger.error(f"Error reading {full_path}: {e}")
218+ processed_files += 1
219+ print(f"\rProcessed {processed_files}/{total_files} files", end="", flush=True)
220+
172221 print() # New line after progress indicator
173222 return '\n'.join(context)
174223
175224 def count_tokens(self, text):
176225 """Count tokens using a simple whitespace-based tokenizer."""
177- return len(text.split())
226+ return len(text.split())
178227
179228 def truncate_context(self, context):
180229 """Truncate context to stay within the token limit."""
@@ -199,12 +248,9 @@ <h2 class="section-title" id="header-classes">Classes</h2>
199248 contents = sorted(path.iterdir())
200249 pointers = [('└── ' if i == len(contents) - 1 else '├── ') for i in range(len(contents))]
201250 for pointer, item in zip(pointers, contents):
202- # Use should_ignore for consistency
203- if self.should_ignore(item):
204- continue
205-
206251 rel_path = item.relative_to(start_dir)
207- tree.append(f"{prefix}{pointer}{rel_path}")
252+ if rel_path in self.included_files:
253+ tree.append(f"{prefix}{pointer}{rel_path}")
208254
209255 if item.is_dir():
210256 add_to_tree(item, prefix + (' ' if pointer == '└── ' else '│ '))
@@ -236,7 +282,7 @@ <h3>Methods</h3>
236282< span > def < span class ="ident "> gather_context</ span > </ span > (< span > self)</ span >
237283</ code > </ dt >
238284< dd >
239- < div class ="desc "> < p > Gather context from relevant files, respecting ignore patterns.</ p > </ div >
285+ < div class ="desc "> < p > Gather context from relevant files, respecting ignore patterns and include paths .</ p > </ div >
240286</ dd >
241287< dt id ="praisonai.ui.context.ContextGatherer.get_context_tree "> < code class ="name flex ">
242288< span > def < span class ="ident "> get_context_tree</ span > </ span > (< span > self)</ span >
@@ -256,6 +302,12 @@ <h3>Methods</h3>
2563024. .gitignore
2573035. Default patterns</ p > </ div >
258304</ dd >
305+ < dt id ="praisonai.ui.context.ContextGatherer.get_include_paths "> < code class ="name flex ">
306+ < span > def < span class ="ident "> get_include_paths</ span > </ span > (< span > self)</ span >
307+ </ code > </ dt >
308+ < dd >
309+ < div class ="desc "> </ div >
310+ </ dd >
259311< dt id ="praisonai.ui.context.ContextGatherer.is_relevant_file "> < code class ="name flex ">
260312< span > def < span class ="ident "> is_relevant_file</ span > </ span > (< span > self, file_path)</ span >
261313</ code > </ dt >
@@ -316,6 +368,7 @@ <h4><code><a title="praisonai.ui.context.ContextGatherer" href="#praisonai.ui.co
316368< li > < code > < a title ="praisonai.ui.context.ContextGatherer.gather_context " href ="#praisonai.ui.context.ContextGatherer.gather_context "> gather_context</ a > </ code > </ li >
317369< li > < code > < a title ="praisonai.ui.context.ContextGatherer.get_context_tree " href ="#praisonai.ui.context.ContextGatherer.get_context_tree "> get_context_tree</ a > </ code > </ li >
318370< li > < code > < a title ="praisonai.ui.context.ContextGatherer.get_ignore_patterns " href ="#praisonai.ui.context.ContextGatherer.get_ignore_patterns "> get_ignore_patterns</ a > </ code > </ li >
371+ < li > < code > < a title ="praisonai.ui.context.ContextGatherer.get_include_paths " href ="#praisonai.ui.context.ContextGatherer.get_include_paths "> get_include_paths</ a > </ code > </ li >
319372< li > < code > < a title ="praisonai.ui.context.ContextGatherer.is_relevant_file " href ="#praisonai.ui.context.ContextGatherer.is_relevant_file "> is_relevant_file</ a > </ code > </ li >
320373< li > < code > < a title ="praisonai.ui.context.ContextGatherer.run " href ="#praisonai.ui.context.ContextGatherer.run "> run</ a > </ code > </ li >
321374< li > < code > < a title ="praisonai.ui.context.ContextGatherer.save_context " href ="#praisonai.ui.context.ContextGatherer.save_context "> save_context</ a > </ code > </ li >
0 commit comments