diff --git a/src/apm_cli/compilation/claude_formatter.py b/src/apm_cli/compilation/claude_formatter.py index f06e5ef3..fe78fdda 100644 --- a/src/apm_cli/compilation/claude_formatter.py +++ b/src/apm_cli/compilation/claude_formatter.py @@ -291,7 +291,10 @@ def _generate_claude_content( sections.append(f"## Files matching `{pattern}`") sections.append("") - for instruction in pattern_instructions: + for instruction in sorted( + pattern_instructions, + key=lambda i: portable_relpath(i.file_path, self.base_dir), + ): content = instruction.content.strip() if content: # Add source attribution comment diff --git a/src/apm_cli/compilation/context_optimizer.py b/src/apm_cli/compilation/context_optimizer.py index 4fc4181d..256ecb32 100644 --- a/src/apm_cli/compilation/context_optimizer.py +++ b/src/apm_cli/compilation/context_optimizer.py @@ -172,8 +172,9 @@ def _get_all_files(self) -> List[Path]: self._file_list_cache = [] for root, dirs, files in os.walk(self.base_dir): # Skip hidden and excluded directories for performance - dirs[:] = [d for d in dirs if not d.startswith('.') and d not in DEFAULT_EXCLUDED_DIRNAMES] - for file in files: + # Sort to guarantee deterministic traversal order across filesystems + dirs[:] = sorted(d for d in dirs if not d.startswith('.') and d not in DEFAULT_EXCLUDED_DIRNAMES) + for file in sorted(files): if not file.startswith('.'): self._file_list_cache.append(Path(root) / file) return self._file_list_cache diff --git a/src/apm_cli/compilation/distributed_compiler.py b/src/apm_cli/compilation/distributed_compiler.py index 48c3214b..c986b8bb 100644 --- a/src/apm_cli/compilation/distributed_compiler.py +++ b/src/apm_cli/compilation/distributed_compiler.py @@ -536,7 +536,10 @@ def _generate_agents_content( sections.append(f"## Files matching `{pattern}`") sections.append("") - for instruction in pattern_instructions: + for instruction in sorted( + pattern_instructions, + key=lambda i: portable_relpath(i.file_path, self.base_dir), + ): content = instruction.content.strip() if content: # Add source attribution for individual instructions diff --git a/src/apm_cli/compilation/template_builder.py b/src/apm_cli/compilation/template_builder.py index e9b945d2..fd8799d1 100644 --- a/src/apm_cli/compilation/template_builder.py +++ b/src/apm_cli/compilation/template_builder.py @@ -34,12 +34,12 @@ def build_conditional_sections(instructions: List[Instruction]) -> str: sections = [] - for pattern, pattern_instructions in pattern_groups.items(): + for pattern, pattern_instructions in sorted(pattern_groups.items()): sections.append(f"## Files matching `{pattern}`") sections.append("") - + # Combine content from all instructions for this pattern - for instruction in pattern_instructions: + for instruction in sorted(pattern_instructions, key=lambda i: portable_relpath(i.file_path, Path.cwd())): content = instruction.content.strip() if content: # Add source file comment before the content