devloop 0.5.1__tar.gz → 0.6.0__tar.gz

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 (147) hide show
  1. {devloop-0.5.1 → devloop-0.6.0}/PKG-INFO +1 -1
  2. {devloop-0.5.1 → devloop-0.6.0}/pyproject.toml +1 -1
  3. devloop-0.6.0/src/devloop/cli/agent_rules.py +274 -0
  4. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/main.py +18 -0
  5. devloop-0.6.0/src/devloop/cli/templates/devloop_agents_template.md +908 -0
  6. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/metrics/__init__.py +10 -0
  7. devloop-0.6.0/src/devloop/metrics/value_metrics.py +362 -0
  8. devloop-0.6.0/src/devloop/providers/artifactory_registry.py +267 -0
  9. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/provider_manager.py +2 -0
  10. devloop-0.6.0/src/devloop/telemetry/__init__.py +5 -0
  11. devloop-0.6.0/src/devloop/telemetry/telemetry_manager.py +281 -0
  12. devloop-0.5.1/src/devloop/cli/templates/devloop_agents_template.md +0 -317
  13. {devloop-0.5.1 → devloop-0.6.0}/LICENSE +0 -0
  14. {devloop-0.5.1 → devloop-0.6.0}/README.md +0 -0
  15. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/__init__.py +0 -0
  16. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/__init__.py +0 -0
  17. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/agent_health_monitor.py +0 -0
  18. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/ci_monitor.py +0 -0
  19. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/code_rabbit.py +0 -0
  20. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/doc_lifecycle.py +0 -0
  21. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/echo.py +0 -0
  22. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/file_logger.py +0 -0
  23. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/formatter.py +0 -0
  24. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/git_commit_assistant.py +0 -0
  25. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/linter.py +0 -0
  26. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/performance_profiler.py +0 -0
  27. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/sandbox_helper.py +0 -0
  28. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/security_scanner.py +0 -0
  29. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/snyk.py +0 -0
  30. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/test_runner.py +0 -0
  31. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/agents/type_checker.py +0 -0
  32. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/__init__.py +0 -0
  33. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/__init__.py +0 -0
  34. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/agent_publish.py +0 -0
  35. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/audit.py +0 -0
  36. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/custom_agents.py +0 -0
  37. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/feedback.py +0 -0
  38. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/marketplace.py +0 -0
  39. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/marketplace_server.py +0 -0
  40. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/metrics.py +0 -0
  41. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/release.py +0 -0
  42. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/summary.py +0 -0
  43. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/telemetry.py +0 -0
  44. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/commands/tools.py +0 -0
  45. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/main_v1.py +0 -0
  46. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/pre_push_check.py +0 -0
  47. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/prerequisites.py +0 -0
  48. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/pyodide_installer.py +0 -0
  49. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/.devloop/tools-registry.json +0 -0
  50. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/claude_commands/README.md +0 -0
  51. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/claude_commands/agent-summary.md +0 -0
  52. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/claude_commands/devloop-findings.md +0 -0
  53. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/claude_commands/devloop-status.md +0 -0
  54. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/claude_commands/extract-findings.md +0 -0
  55. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/claude_commands/verify-work.md +0 -0
  56. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/git_hooks/pre-commit +0 -0
  57. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/git_hooks/pre-commit-checks +0 -0
  58. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/git_hooks/pre-push +0 -0
  59. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/supervisor/devloop.conf +0 -0
  60. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/cli/templates/systemd/devloop.service +0 -0
  61. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/collectors/__init__.py +0 -0
  62. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/collectors/base.py +0 -0
  63. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/collectors/filesystem.py +0 -0
  64. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/collectors/git.py +0 -0
  65. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/collectors/manager.py +0 -0
  66. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/collectors/process.py +0 -0
  67. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/collectors/system.py +0 -0
  68. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/__init__.py +0 -0
  69. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/action_logger.py +0 -0
  70. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/agent.py +0 -0
  71. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/agent_audit_logger.py +0 -0
  72. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/agent_template.py +0 -0
  73. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/amp_integration.py +0 -0
  74. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/amp_thread_mapper.py +0 -0
  75. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/auto_fix.py +0 -0
  76. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/backup_manager.py +0 -0
  77. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/claude_adapter.py +0 -0
  78. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/config.py +0 -0
  79. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/config_schema.py +0 -0
  80. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/context.py +0 -0
  81. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/context_store.py +0 -0
  82. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/contextual_feedback.py +0 -0
  83. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/custom_agent.py +0 -0
  84. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/daemon_health.py +0 -0
  85. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/debug_trace.py +0 -0
  86. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/error_handler.py +0 -0
  87. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/error_notifier.py +0 -0
  88. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/event.py +0 -0
  89. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/event_replayer.py +0 -0
  90. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/event_store.py +0 -0
  91. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/feedback.py +0 -0
  92. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/file_lock_manager.py +0 -0
  93. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/learning.py +0 -0
  94. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/manager.py +0 -0
  95. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/operational_health.py +0 -0
  96. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/pattern_analyzer.py +0 -0
  97. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/pattern_detector.py +0 -0
  98. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/performance.py +0 -0
  99. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/proactive_feedback.py +0 -0
  100. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/summary_formatter.py +0 -0
  101. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/summary_generator.py +0 -0
  102. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/telemetry.py +0 -0
  103. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/tool_dependencies.py +0 -0
  104. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/tool_registry.py +0 -0
  105. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/tool_runner.py +0 -0
  106. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/core/transactional_io.py +0 -0
  107. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/integrations/__init__.py +0 -0
  108. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/integrations/beads_integration.py +0 -0
  109. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/lsp/__init__.py +0 -0
  110. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/lsp/__main__.py +0 -0
  111. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/lsp/mapper.py +0 -0
  112. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/lsp/server.py +0 -0
  113. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/__init__.py +0 -0
  114. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/api.py +0 -0
  115. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/cache.py +0 -0
  116. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/http_server.py +0 -0
  117. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/installer.py +0 -0
  118. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/metadata.py +0 -0
  119. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/publisher.py +0 -0
  120. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/registry.py +0 -0
  121. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/registry_client.py +0 -0
  122. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/reviews.py +0 -0
  123. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/search.py +0 -0
  124. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/marketplace/signing.py +0 -0
  125. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/metrics/dora.py +0 -0
  126. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/__init__.py +0 -0
  127. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/ci_provider.py +0 -0
  128. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/circleci_provider.py +0 -0
  129. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/github_actions_provider.py +0 -0
  130. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/gitlab_ci_provider.py +0 -0
  131. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/jenkins_provider.py +0 -0
  132. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/pypi_registry.py +0 -0
  133. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/providers/registry_provider.py +0 -0
  134. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/release/__init__.py +0 -0
  135. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/release/release_manager.py +0 -0
  136. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/__init__.py +0 -0
  137. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/audit_logger.py +0 -0
  138. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/bubblewrap_sandbox.py +0 -0
  139. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/cgroups_helper.py +0 -0
  140. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/factory.py +0 -0
  141. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/no_sandbox.py +0 -0
  142. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/package.json +0 -0
  143. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/path_validator.py +0 -0
  144. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/pyodide_runner.js +0 -0
  145. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/pyodide_sandbox.py +0 -0
  146. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/sandbox.py +0 -0
  147. {devloop-0.5.1 → devloop-0.6.0}/src/devloop/security/token_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devloop
3
- Version: 0.5.1
3
+ Version: 0.6.0
4
4
  Summary: Intelligent background agents for development workflow automation
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "devloop"
3
- version = "0.5.1"
3
+ version = "0.6.0"
4
4
  description = "Intelligent background agents for development workflow automation"
5
5
  authors = ["DevLoop Contributors <devloop@example.com>"]
6
6
  license = "MIT"
@@ -0,0 +1,274 @@
1
+ """Agent rules configuration management and merging."""
2
+
3
+ from pathlib import Path
4
+ from typing import Any, Dict, List, Optional
5
+
6
+ import yaml
7
+
8
+
9
+ class AgentRules:
10
+ """Manages per-agent rules and configuration files."""
11
+
12
+ def __init__(self, agents_dir: str = ".agents/agents"):
13
+ """Initialize agent rules manager.
14
+
15
+ Args:
16
+ agents_dir: Directory containing agent subdirectories with rules.yaml files
17
+ """
18
+ self.agents_dir = agents_dir
19
+ self.agents_path = Path(agents_dir)
20
+
21
+ def discover_agents(self) -> List[str]:
22
+ """Discover all agents with rules.yaml files.
23
+
24
+ Returns:
25
+ List of agent names
26
+ """
27
+ agents = []
28
+ if self.agents_path.exists():
29
+ for agent_dir in self.agents_path.iterdir():
30
+ if agent_dir.is_dir():
31
+ rules_file = agent_dir / "rules.yaml"
32
+ if rules_file.exists():
33
+ agents.append(agent_dir.name)
34
+ return sorted(agents)
35
+
36
+ def load_agent_rules(self, agent_name: str) -> Optional[Dict[str, Any]]:
37
+ """Load rules for a specific agent.
38
+
39
+ Args:
40
+ agent_name: Name of the agent
41
+
42
+ Returns:
43
+ Parsed rules dictionary or None if not found
44
+ """
45
+ rules_file = self.agents_path / agent_name / "rules.yaml"
46
+ if not rules_file.exists():
47
+ return None
48
+
49
+ try:
50
+ with open(rules_file) as f:
51
+ return yaml.safe_load(f) or {}
52
+ except (IOError, yaml.YAMLError):
53
+ return None
54
+
55
+ def load_all_rules(self) -> Dict[str, Dict[str, Any]]:
56
+ """Load rules for all discovered agents.
57
+
58
+ Returns:
59
+ Dictionary mapping agent names to their rules
60
+ """
61
+ rules = {}
62
+ for agent_name in self.discover_agents():
63
+ agent_rules = self.load_agent_rules(agent_name)
64
+ if agent_rules:
65
+ rules[agent_name] = agent_rules
66
+ return rules
67
+
68
+ def generate_template(self) -> str:
69
+ """Generate AGENTS.md template from all agent rules.
70
+
71
+ Returns:
72
+ Markdown template ready for merging with existing AGENTS.md
73
+ """
74
+ all_rules = self.load_all_rules()
75
+ if not all_rules:
76
+ return ""
77
+
78
+ template_parts = []
79
+ template_parts.append("# Auto-Generated Agent Configuration\n")
80
+ template_parts.append(
81
+ "This section was generated from agent rules. "
82
+ "Do not edit manually - update `.agents/agents/*/rules.yaml` instead.\n\n"
83
+ )
84
+
85
+ # Section: Preflight Tasks
86
+ preflight_commands = []
87
+ for agent_name, rules in sorted(all_rules.items()):
88
+ if "preflight" in rules and rules["preflight"]:
89
+ preflight_commands.extend(rules["preflight"])
90
+
91
+ if preflight_commands:
92
+ template_parts.append("## Preflight Checklist\n\n")
93
+ template_parts.append(
94
+ "Run these commands at the start of each session:\n\n"
95
+ )
96
+ for cmd in preflight_commands:
97
+ template_parts.append(f"```bash\n{cmd}\n```\n\n")
98
+
99
+ # Section: Dependencies
100
+ all_dependencies = []
101
+ for agent_name, rules in sorted(all_rules.items()):
102
+ if "dependencies" in rules and rules["dependencies"]:
103
+ for dep in rules["dependencies"]:
104
+ all_dependencies.append(dep)
105
+
106
+ if all_dependencies:
107
+ template_parts.append("## Dependencies\n\n")
108
+ for dep in all_dependencies:
109
+ requires = dep.get("requires", "unknown")
110
+ version = dep.get("version", "any")
111
+ template_parts.append(f"- **{requires}**: {version}\n")
112
+ template_parts.append("\n")
113
+
114
+ # Section: DevLoop Hints
115
+ all_hints = []
116
+ for agent_name, rules in sorted(all_rules.items()):
117
+ if "devloop_hints" in rules and rules["devloop_hints"]:
118
+ for hint in rules["devloop_hints"]:
119
+ all_hints.append(hint)
120
+
121
+ if all_hints:
122
+ template_parts.append("## Development Hints\n\n")
123
+ for hint in all_hints:
124
+ title = hint.get("title", "Tip")
125
+ description = hint.get("description", "")
126
+ workaround = hint.get("workaround")
127
+
128
+ template_parts.append(f"### {title}\n\n")
129
+ template_parts.append(f"{description}\n\n")
130
+ if workaround:
131
+ template_parts.append("**Workaround**:\n\n")
132
+ template_parts.append(f"```bash\n{workaround}\n```\n\n")
133
+
134
+ return "".join(template_parts)
135
+
136
+ @staticmethod
137
+ def merge_templates(existing_md: str, generated_template: str) -> str:
138
+ """Intelligently merge generated template with existing AGENTS.md.
139
+
140
+ This function:
141
+ 1. Detects and preserves existing custom content
142
+ 2. Skips duplicate sections
143
+ 3. Merges related content by topic
144
+ 4. Maintains semantic structure
145
+
146
+ Args:
147
+ existing_md: Current AGENTS.md content
148
+ generated_template: Generated template from agent rules
149
+
150
+ Returns:
151
+ Merged AGENTS.md content
152
+ """
153
+ # If no existing content, just return generated
154
+ if not existing_md.strip():
155
+ return generated_template
156
+
157
+ # Parse both documents into sections
158
+ existing_sections = _parse_markdown_sections(existing_md)
159
+
160
+ # Start with generated content (it's the "source of truth" from rules)
161
+ merged_parts = []
162
+
163
+ # Detect auto-generated marker
164
+ if "Auto-Generated Agent Configuration" in existing_md:
165
+ # Remove old auto-generated section
166
+ existing_md = _remove_section(
167
+ existing_md, "Auto-Generated Agent Configuration"
168
+ )
169
+
170
+ # Add generated content first
171
+ merged_parts.append(generated_template)
172
+
173
+ # Then add custom content from existing file (preserve user modifications)
174
+ custom_sections = [
175
+ sec
176
+ for sec in existing_sections
177
+ if not _is_auto_generated_section(sec["title"])
178
+ ]
179
+
180
+ if custom_sections:
181
+ merged_parts.append("\n# Custom Configuration\n\n")
182
+ for section in custom_sections:
183
+ merged_parts.append(f"## {section['title']}\n\n")
184
+ merged_parts.append(section["content"])
185
+ merged_parts.append("\n")
186
+
187
+ return "".join(merged_parts)
188
+
189
+
190
+ def _parse_markdown_sections(content: str) -> List[Dict[str, str]]:
191
+ """Parse markdown into sections.
192
+
193
+ Args:
194
+ content: Markdown content
195
+
196
+ Returns:
197
+ List of sections with title and content
198
+ """
199
+ sections = []
200
+ current_title = "Preamble"
201
+ current_content = []
202
+
203
+ for line in content.split("\n"):
204
+ if line.startswith("## "):
205
+ # Save previous section
206
+ if current_content or current_title != "Preamble":
207
+ sections.append(
208
+ {
209
+ "title": current_title,
210
+ "content": "\n".join(current_content),
211
+ }
212
+ )
213
+ # Start new section
214
+ current_title = line[3:].strip()
215
+ current_content = []
216
+ else:
217
+ current_content.append(line)
218
+
219
+ # Save last section
220
+ if current_content or current_title != "Preamble":
221
+ sections.append(
222
+ {
223
+ "title": current_title,
224
+ "content": "\n".join(current_content),
225
+ }
226
+ )
227
+
228
+ return sections
229
+
230
+
231
+ def _is_auto_generated_section(title: str) -> bool:
232
+ """Check if a section is auto-generated.
233
+
234
+ Args:
235
+ title: Section title
236
+
237
+ Returns:
238
+ True if section is auto-generated
239
+ """
240
+ auto_sections = {
241
+ "Preflight Checklist",
242
+ "Dependencies",
243
+ "Development Hints",
244
+ "Agent Configuration",
245
+ "Auto-Generated Agent Configuration",
246
+ }
247
+ return title in auto_sections
248
+
249
+
250
+ def _remove_section(content: str, section_title: str) -> str:
251
+ """Remove a section from markdown content.
252
+
253
+ Args:
254
+ content: Markdown content
255
+ section_title: Title of section to remove
256
+
257
+ Returns:
258
+ Content with section removed
259
+ """
260
+ sections = _parse_markdown_sections(content)
261
+ remaining = [
262
+ sec for sec in sections if sec["title"].lower() != section_title.lower()
263
+ ]
264
+
265
+ # Reconstruct
266
+ parts = []
267
+ for section in remaining:
268
+ if section["title"] != "Preamble":
269
+ parts.append(f"## {section['title']}\n")
270
+ parts.append(section["content"])
271
+ if section != remaining[-1]:
272
+ parts.append("\n")
273
+
274
+ return "\n".join(parts)
@@ -685,6 +685,24 @@ def init(
685
685
  missing_sections.append("Token security")
686
686
  if "Development Discipline" not in content:
687
687
  missing_sections.append("Development discipline")
688
+ if "Pre-Flight Development Checklist" not in content:
689
+ missing_sections.append("Pre-flight checklist")
690
+ if "CI Verification" not in content and "Pre-Push Hook" not in content:
691
+ missing_sections.append("CI verification (pre-push hook)")
692
+ if "Documentation Practices" not in content:
693
+ missing_sections.append("Documentation practices")
694
+ if "Publishing & Security Considerations" not in content:
695
+ missing_sections.append("Publishing & security considerations")
696
+ if "Release Process" not in content:
697
+ missing_sections.append("Release process")
698
+ if "Configuration" not in content:
699
+ missing_sections.append("Configuration (logging, agents)")
700
+ if "Security & Privacy" not in content:
701
+ missing_sections.append("Security & privacy")
702
+ if "Success Metrics" not in content:
703
+ missing_sections.append("Success metrics")
704
+ if "Future Considerations" not in content:
705
+ missing_sections.append("Future considerations")
688
706
 
689
707
  needs_devloop_content = len(missing_sections) > 0
690
708