source-kb 0.2.2__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 (228) hide show
  1. cli/__init__.py +50 -0
  2. cli/__main__.py +5 -0
  3. cli/commands/__init__.py +1 -0
  4. cli/commands/anchor_fix.py +47 -0
  5. cli/commands/diff_doc.py +52 -0
  6. cli/commands/dispatch.py +77 -0
  7. cli/commands/extract.py +72 -0
  8. cli/commands/file_list.py +74 -0
  9. cli/commands/index.py +84 -0
  10. cli/commands/lock.py +89 -0
  11. cli/commands/merge.py +60 -0
  12. cli/commands/merge_delta.py +19 -0
  13. cli/commands/metadata.py +24 -0
  14. cli/commands/pipeline.py +45 -0
  15. cli/commands/post_merge.py +43 -0
  16. cli/commands/query.py +52 -0
  17. cli/commands/render.py +101 -0
  18. cli/commands/scan_repos.py +46 -0
  19. cli/commands/setup.py +94 -0
  20. cli/commands/split.py +196 -0
  21. cli/commands/stale_files.py +98 -0
  22. cli/commands/validate.py +191 -0
  23. core/__init__.py +32 -0
  24. core/config.py +261 -0
  25. core/docs/__init__.py +7 -0
  26. core/docs/section_updater.py +286 -0
  27. core/docs/shared.py +149 -0
  28. core/git.py +294 -0
  29. core/interfaces.py +249 -0
  30. core/monitor/__init__.py +5 -0
  31. core/monitor/progress.py +83 -0
  32. core/monitor/prompt_store.py +49 -0
  33. core/paths.py +141 -0
  34. core/preset.py +237 -0
  35. core/preset_accessors.py +202 -0
  36. core/preset_classify.py +132 -0
  37. core/preset_hooks.py +129 -0
  38. core/preset_profile.py +89 -0
  39. core/prompt/__init__.py +7 -0
  40. core/prompt/__main__.py +147 -0
  41. core/prompt/content.py +320 -0
  42. core/prompt/context_manager.py +164 -0
  43. core/prompt/renderer.py +236 -0
  44. core/prompt/response_parser.py +274 -0
  45. core/prompt/templates.py +357 -0
  46. core/prompt/validate_parity.py +162 -0
  47. core/prompt/variables.py +339 -0
  48. core/rag/__init__.py +22 -0
  49. core/rag/__main__.py +136 -0
  50. core/rag/bm25_index.py +268 -0
  51. core/rag/chunker.py +273 -0
  52. core/rag/embedder.py +151 -0
  53. core/rag/indexer.py +292 -0
  54. core/rag/loader.py +89 -0
  55. core/rag/retriever.py +82 -0
  56. core/skeleton/__init__.py +11 -0
  57. core/skeleton/__main__.py +934 -0
  58. core/skeleton/anchor_fix.py +250 -0
  59. core/skeleton/classify.py +331 -0
  60. core/skeleton/cmd_anchor_fix.py +43 -0
  61. core/skeleton/cmd_diff_doc.py +44 -0
  62. core/skeleton/cmd_lock.py +87 -0
  63. core/skeleton/cmd_merge_delta.py +41 -0
  64. core/skeleton/community.py +233 -0
  65. core/skeleton/dependency_graph.py +306 -0
  66. core/skeleton/diff_doc.py +248 -0
  67. core/skeleton/dispatch.py +273 -0
  68. core/skeleton/dispatch_render.py +319 -0
  69. core/skeleton/dispatch_source.py +111 -0
  70. core/skeleton/extract.py +218 -0
  71. core/skeleton/extract_methods.py +298 -0
  72. core/skeleton/file_list.py +239 -0
  73. core/skeleton/impact.py +278 -0
  74. core/skeleton/jar_download.py +177 -0
  75. core/skeleton/jar_resolver.py +186 -0
  76. core/skeleton/loader.py +162 -0
  77. core/skeleton/merge.py +278 -0
  78. core/skeleton/merge_delta.py +229 -0
  79. core/skeleton/metadata.py +96 -0
  80. core/skeleton/metadata_builders.py +264 -0
  81. core/skeleton/module_dag.py +330 -0
  82. core/skeleton/parsers/__init__.py +71 -0
  83. core/skeleton/parsers/jqassistant.py +300 -0
  84. core/skeleton/parsers/jqassistant_cypher.py +225 -0
  85. core/skeleton/parsers/regex.py +171 -0
  86. core/skeleton/parsers/treesitter.py +324 -0
  87. core/skeleton/parsers/treesitter_java.py +284 -0
  88. core/skeleton/parsers/treesitter_multi.py +289 -0
  89. core/skeleton/pom_parser.py +299 -0
  90. core/skeleton/post_merge.py +295 -0
  91. core/skeleton/post_merge_llm.py +82 -0
  92. core/skeleton/query.py +195 -0
  93. core/skeleton/shard_context.py +177 -0
  94. core/skeleton/split.py +180 -0
  95. core/skeleton/split_cache.py +107 -0
  96. core/skeleton/split_feedback.py +174 -0
  97. core/skeleton/split_plan.py +219 -0
  98. core/skeleton/split_plan_helpers.py +305 -0
  99. core/skeleton/split_plan_llm.py +274 -0
  100. core/utils.py +135 -0
  101. core/validators/__init__.py +65 -0
  102. core/validators/__main__.py +215 -0
  103. core/validators/consistency.py +203 -0
  104. core/validators/coverage.py +171 -0
  105. core/validators/duplicates.py +76 -0
  106. core/validators/engine.py +224 -0
  107. core/validators/links.py +76 -0
  108. core/validators/sampling.py +169 -0
  109. core/validators/structure.py +144 -0
  110. engine/__init__.py +7 -0
  111. engine/assembler.py +231 -0
  112. engine/confirm.py +65 -0
  113. engine/dedup.py +106 -0
  114. engine/main.py +211 -0
  115. engine/pipeline/__init__.py +163 -0
  116. engine/pipeline/recovery.py +250 -0
  117. engine/pipeline/steps/__init__.py +23 -0
  118. engine/pipeline/steps/audit.py +220 -0
  119. engine/pipeline/steps/audit_apply.py +195 -0
  120. engine/pipeline/steps/audit_helpers.py +155 -0
  121. engine/pipeline/steps/classify_llm.py +236 -0
  122. engine/pipeline/steps/classify_prompt.py +223 -0
  123. engine/pipeline/steps/finalize.py +160 -0
  124. engine/pipeline/steps/generate.py +169 -0
  125. engine/pipeline/steps/generate_batch.py +197 -0
  126. engine/pipeline/steps/generate_recovery.py +170 -0
  127. engine/pipeline/steps/llm_plan_split.py +253 -0
  128. engine/pipeline/steps/lock.py +64 -0
  129. engine/pipeline/steps/preflight.py +237 -0
  130. engine/pipeline/steps/preflight_adjust.py +147 -0
  131. engine/pipeline/steps/pregenerate.py +130 -0
  132. engine/pipeline/steps/quality.py +81 -0
  133. engine/pipeline/steps/skeleton.py +149 -0
  134. engine/pipeline/steps/source.py +163 -0
  135. engine/pipeline/steps/sync.py +117 -0
  136. engine/pipeline/steps/sync_finalize.py +237 -0
  137. engine/pipeline/steps/sync_update.py +341 -0
  138. engine/pipelines.py +91 -0
  139. engine/runner.py +335 -0
  140. engine/strategies/__init__.py +86 -0
  141. engine/strategies/api.py +128 -0
  142. engine/strategies/delegated.py +50 -0
  143. engine/strategies/dryrun.py +25 -0
  144. engine/two_phase.py +143 -0
  145. mcp_server/__init__.py +73 -0
  146. mcp_server/__main__.py +5 -0
  147. mcp_server/tools/__init__.py +1 -0
  148. mcp_server/tools/config.py +63 -0
  149. mcp_server/tools/discovery.py +276 -0
  150. mcp_server/tools/generation.py +184 -0
  151. mcp_server/tools/planning.py +144 -0
  152. mcp_server/tools/source.py +175 -0
  153. mcp_server/tools/validation.py +140 -0
  154. mcp_server/tools/workflow.py +166 -0
  155. mcp_server/workflow_loader.py +204 -0
  156. presets/generic/audit_dimensions.md +132 -0
  157. presets/generic/doc_types.yaml +152 -0
  158. presets/generic/preset.yaml +115 -0
  159. presets/java-spring/audit_dimensions.md +228 -0
  160. presets/java-spring/audit_dimensions.yaml +203 -0
  161. presets/java-spring/doc_types.yaml +269 -0
  162. presets/java-spring/hooks.py +122 -0
  163. presets/java-spring/preset.yaml +341 -0
  164. presets/java-spring/templates/README.md +34 -0
  165. presets/java-spring/templates/audit-system.md +15 -0
  166. presets/java-spring/templates/subagent-aop.md +105 -0
  167. presets/java-spring/templates/subagent-api.md +63 -0
  168. presets/java-spring/templates/subagent-architecture.md +111 -0
  169. presets/java-spring/templates/subagent-async-events.md +107 -0
  170. presets/java-spring/templates/subagent-audit-api-contracts.md +40 -0
  171. presets/java-spring/templates/subagent-audit-architecture.md +38 -0
  172. presets/java-spring/templates/subagent-audit-business.md +40 -0
  173. presets/java-spring/templates/subagent-audit-data-models.md +40 -0
  174. presets/java-spring/templates/subagent-business.md +129 -0
  175. presets/java-spring/templates/subagent-caching.md +75 -0
  176. presets/java-spring/templates/subagent-database-access.md +114 -0
  177. presets/java-spring/templates/subagent-enum.md +75 -0
  178. presets/java-spring/templates/subagent-error-handling.md +91 -0
  179. presets/java-spring/templates/subagent-external-integrations.md +80 -0
  180. presets/java-spring/templates/subagent-index.md +122 -0
  181. presets/java-spring/templates/subagent-messaging.md +97 -0
  182. presets/java-spring/templates/subagent-model.md +88 -0
  183. presets/java-spring/templates/subagent-observability.md +91 -0
  184. presets/java-spring/templates/subagent-scheduled.md +81 -0
  185. presets/java-spring/templates/subagent-security.md +102 -0
  186. presets/java-spring/templates/subagent-structure.md +101 -0
  187. presets/java-spring/templates/subagent-sync-section.md +34 -0
  188. presets/java-spring/templates/subagent-utils.md +73 -0
  189. presets/java-spring/templates/sync-system.md +8 -0
  190. presets/java-spring/workflow-extensions.md +112 -0
  191. skills/__init__.py +1 -0
  192. skills/_shared/README.md +30 -0
  193. skills/_shared/doc-coverage-shared.md +134 -0
  194. skills/_shared/doc-quality-standard.md +1058 -0
  195. skills/_shared/doc-subagent-rules.md +762 -0
  196. skills/_shared/windows-compat.md +89 -0
  197. skills/kb-audit/SKILL.md +52 -0
  198. skills/kb-audit/rules.md +88 -0
  199. skills/kb-audit/steps/step-01-prepare.md +75 -0
  200. skills/kb-audit/steps/step-02-audit.md +96 -0
  201. skills/kb-audit/steps/step-03-verify.md +65 -0
  202. skills/kb-audit/steps/step-04-report.md +64 -0
  203. skills/kb-init/SKILL.md +146 -0
  204. skills/kb-init/rules.md +187 -0
  205. skills/kb-init/steps/step-01-scope.md +62 -0
  206. skills/kb-init/steps/step-02-source.md +410 -0
  207. skills/kb-init/steps/step-03-generate.md +307 -0
  208. skills/kb-init/steps/step-04-quality.md +92 -0
  209. skills/kb-init/steps/step-05-finalize.md +132 -0
  210. skills/kb-init/templates/core/execution-modes.md +29 -0
  211. skills/kb-init/templates/core/output-only.md +4 -0
  212. skills/kb-init/templates/core/readwrite.md +33 -0
  213. skills/kb-search/SKILL.md +138 -0
  214. skills/kb-search/rules.md +64 -0
  215. skills/kb-sync/SKILL.md +43 -0
  216. skills/kb-sync/rules.md +70 -0
  217. skills/kb-sync/scripts/rebuild_module.py +91 -0
  218. skills/kb-sync/scripts/scan_repos.py +687 -0
  219. skills/kb-sync/steps/step-01-detect.md +72 -0
  220. skills/kb-sync/steps/step-02-update.md +71 -0
  221. skills/kb-sync/steps/step-03-verify.md +47 -0
  222. skills/kb-sync/steps/step-04-finalize.md +52 -0
  223. source_kb-0.2.2.dist-info/METADATA +194 -0
  224. source_kb-0.2.2.dist-info/RECORD +228 -0
  225. source_kb-0.2.2.dist-info/WHEEL +5 -0
  226. source_kb-0.2.2.dist-info/entry_points.txt +3 -0
  227. source_kb-0.2.2.dist-info/licenses/LICENSE +21 -0
  228. source_kb-0.2.2.dist-info/top_level.txt +6 -0
@@ -0,0 +1,357 @@
1
+ """Prompt template dataclass and registry.
2
+
3
+ Provides parameterized prompt templates for LLM steps (sync section-update,
4
+ audit doc-type checks, etc.). Templates are registered by name and looked up
5
+ at runtime.
6
+
7
+ Usage:
8
+ from core.prompt.templates import PromptTemplate, register, get, list_templates
9
+
10
+ template = get("sync:section-update")
11
+ system, user = template.render(doc_type="business-logic", ...)
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass
17
+
18
+
19
+ @dataclass
20
+ class PromptTemplate:
21
+ """A parameterized prompt template with system and user parts."""
22
+
23
+ name: str
24
+ system_template: str
25
+ user_template: str
26
+
27
+ def render(self, **kwargs: str) -> tuple[str, str]:
28
+ """Render both templates with provided variables.
29
+
30
+ Missing keys render as empty string (safe fallback).
31
+ Returns (system_prompt, user_prompt).
32
+ """
33
+ safe = _SafeDict(kwargs)
34
+ return (
35
+ self.system_template.format_map(safe),
36
+ self.user_template.format_map(safe),
37
+ )
38
+
39
+
40
+ class _SafeDict(dict):
41
+ """format_map fallback — missing keys render as empty string."""
42
+ def __missing__(self, key: str) -> str:
43
+ return ""
44
+
45
+
46
+ # ---------------------------------------------------------------------------
47
+ # Registry
48
+ # ---------------------------------------------------------------------------
49
+
50
+ _REGISTRY: dict[str, PromptTemplate] = {}
51
+
52
+
53
+ def register(template: PromptTemplate) -> PromptTemplate:
54
+ """Register a template by name. Returns the template for decorator use."""
55
+ _REGISTRY[template.name] = template
56
+ return template
57
+
58
+
59
+ def get(name: str) -> PromptTemplate:
60
+ """Look up a registered template by name. Raises KeyError if not found."""
61
+ if name not in _REGISTRY:
62
+ available = ", ".join(sorted(_REGISTRY.keys()))
63
+ raise KeyError(f"Template '{name}' not found. Available: {available}")
64
+ return _REGISTRY[name]
65
+
66
+
67
+ def list_templates() -> list[str]:
68
+ """Return sorted list of all registered template names."""
69
+ return sorted(_REGISTRY.keys())
70
+
71
+
72
+ # ---------------------------------------------------------------------------
73
+ # Built-in templates: Audit
74
+ # ---------------------------------------------------------------------------
75
+
76
+ _AUDIT_SYSTEM_COMMON = (
77
+ "You are a knowledge base auditor. Compare the document against source code "
78
+ "and report findings.\n"
79
+ 'Return ONLY a JSON object: {{"findings": [{{"dimension": "...", '
80
+ '"status": "pass|fail", "detail": "...", "fix": "..."}}]}}\n'
81
+ '- "pass": document matches source code for this dimension\n'
82
+ '- "fail": inconsistency found — "detail" explains what\'s wrong, '
83
+ '"fix" gives the corrected content\n'
84
+ "- Be precise: cite specific class/method/field names\n"
85
+ "- Output in Chinese"
86
+ )
87
+
88
+ register(PromptTemplate(
89
+ name="audit:source-tree",
90
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: source-tree-analysis.md\n"
91
+ "Dimensions: 1.file completeness 2.directory structure 3.file responsibility "
92
+ "4.file count 5.new/deleted files",
93
+ user_template=(
94
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
95
+ "Source skeleton:\n{skeleton}\n\nActual file list:\n{file_list}\n\n"
96
+ "Audit source-tree-analysis.md against source code."
97
+ ),
98
+ ))
99
+
100
+ register(PromptTemplate(
101
+ name="audit:data-models",
102
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: data-models.md\n"
103
+ "Dimensions: 1.entity completeness 2.field consistency 3.annotation accuracy "
104
+ "4.table name mapping 5.DTO/VO coverage 6.enum values 7.inheritance",
105
+ user_template=(
106
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
107
+ "Entity/DTO/VO skeleton:\n{skeleton}\n\nSource snippets:\n{source_snippets}\n\n"
108
+ "Audit data-models.md against source code."
109
+ ),
110
+ ))
111
+
112
+ register(PromptTemplate(
113
+ name="audit:api-contracts",
114
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: api-contracts.md\n"
115
+ "Dimensions: 1.interface completeness 2.URL path 3.HTTP method 4.request params "
116
+ "5.response type 6.error codes 7.Feign fallback 8.permission annotations",
117
+ user_template=(
118
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
119
+ "Controller/API skeleton:\n{skeleton}\n\n"
120
+ "Audit api-contracts.md against source code."
121
+ ),
122
+ ))
123
+
124
+ register(PromptTemplate(
125
+ name="audit:architecture",
126
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: architecture.md\n"
127
+ "Dimensions: 1.tech stack versions 2.dependency list 3.layer structure "
128
+ "4.middleware config 5.component relationships 6.config items",
129
+ user_template=(
130
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
131
+ "pom.xml:\n{pom_xml}\n\nConfig (yml):\n{yml_config}\n\n"
132
+ "Config class skeleton:\n{skeleton}\n\n"
133
+ "Audit architecture.md against source code."
134
+ ),
135
+ ))
136
+
137
+ register(PromptTemplate(
138
+ name="audit:business-logic",
139
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: business-logic.md\n"
140
+ "Dimensions (10 method-level): 1.method purpose 2.parameter semantics "
141
+ "3.return value meaning 4.core logic flow 5.branch condition rationale "
142
+ "6.exception handling 7.external dependency 8.state mutation "
143
+ "9.performance/concurrency 10.edge case coverage "
144
+ "Plus: 11.reference integrity 12.dedup compliance",
145
+ user_template=(
146
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
147
+ "Service skeleton:\n{skeleton}\n\nSource code (high-complexity methods):\n"
148
+ "{source_code}\n\nNeutral doc headings:\n{neutral_doc_headings}\n\n"
149
+ "Audit business-logic.md against source code."
150
+ ),
151
+ ))
152
+
153
+ register(PromptTemplate(
154
+ name="audit:messaging",
155
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: messaging.md\n"
156
+ "Dimensions: 1.topic completeness 2.message body structure "
157
+ "3.consumer groupId 4.producer/consumer relationships",
158
+ user_template=(
159
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
160
+ "Messaging skeleton:\n{skeleton}\n\n"
161
+ "Audit messaging.md against source code."
162
+ ),
163
+ ))
164
+
165
+ register(PromptTemplate(
166
+ name="audit:caching",
167
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: caching.md\n"
168
+ "Dimensions: 1.key completeness 2.TTL accuracy 3.data type correctness",
169
+ user_template=(
170
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
171
+ "Caching skeleton:\n{skeleton}\n\nKey constants:\n{key_constants}\n\n"
172
+ "Audit caching.md against source code."
173
+ ),
174
+ ))
175
+
176
+ register(PromptTemplate(
177
+ name="audit:enums",
178
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: enums-and-constants.md\n"
179
+ "Dimensions: 1.enum completeness 2.enum value accuracy "
180
+ "3.constant value correctness 4.usage context",
181
+ user_template=(
182
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
183
+ "Enum/constant skeleton:\n{skeleton}\n\n"
184
+ "Audit enums-and-constants.md against source code."
185
+ ),
186
+ ))
187
+
188
+ register(PromptTemplate(
189
+ name="audit:utils",
190
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: utils.md\n"
191
+ "Dimensions: 1.utility class completeness 2.method signature accuracy "
192
+ "3.usage context",
193
+ user_template=(
194
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
195
+ "Utility skeleton:\n{skeleton}\n\n"
196
+ "Audit utils.md against source code."
197
+ ),
198
+ ))
199
+
200
+ register(PromptTemplate(
201
+ name="audit:external",
202
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: external-integrations.md\n"
203
+ "Dimensions: 1.integration completeness 2.endpoint/URL accuracy "
204
+ "3.request/response format 4.error handling",
205
+ user_template=(
206
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
207
+ "Integration skeleton:\n{skeleton}\n\n"
208
+ "Audit external-integrations.md against source code."
209
+ ),
210
+ ))
211
+
212
+ register(PromptTemplate(
213
+ name="audit:database",
214
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: database-access.md\n"
215
+ "Dimensions: 1.mapper completeness 2.SQL semantics accuracy "
216
+ "3.transaction boundaries 4.pagination params 5.batch operations 6.table mapping",
217
+ user_template=(
218
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
219
+ "DAO/Mapper skeleton:\n{skeleton}\n\nSource snippets:\n{source_snippets}\n\n"
220
+ "Audit database-access.md against source code."
221
+ ),
222
+ ))
223
+
224
+ register(PromptTemplate(
225
+ name="audit:scheduled",
226
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: scheduled-tasks.md\n"
227
+ "Dimensions: 1.task completeness 2.cron expression accuracy "
228
+ "3.execution frequency 4.idempotency 5.error handling 6.sharding strategy",
229
+ user_template=(
230
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
231
+ "Scheduled task skeleton:\n{skeleton}\n\n"
232
+ "Audit scheduled-tasks.md against source code."
233
+ ),
234
+ ))
235
+
236
+ register(PromptTemplate(
237
+ name="audit:error",
238
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: error-handling.md\n"
239
+ "Dimensions: 1.exception class completeness 2.hierarchy structure "
240
+ "3.error code mapping 4.global handler logic 5.user-facing messages",
241
+ user_template=(
242
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
243
+ "Exception skeleton:\n{skeleton}\n\n"
244
+ "Audit error-handling.md against source code."
245
+ ),
246
+ ))
247
+
248
+ register(PromptTemplate(
249
+ name="audit:security",
250
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: security.md\n"
251
+ "Dimensions: 1.auth flow completeness 2.token mechanism "
252
+ "3.permission model 4.filter chain order 5.permission identifiers",
253
+ user_template=(
254
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
255
+ "Security skeleton:\n{skeleton}\n\n"
256
+ "Audit security.md against source code."
257
+ ),
258
+ ))
259
+
260
+ register(PromptTemplate(
261
+ name="audit:aop",
262
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: aop-and-interceptors.md\n"
263
+ "Dimensions: 1.aspect completeness 2.pointcut expression accuracy "
264
+ "3.execution order 4.interceptor chain 5.advice type logic",
265
+ user_template=(
266
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
267
+ "AOP/Interceptor skeleton:\n{skeleton}\n\n"
268
+ "Audit aop-and-interceptors.md against source code."
269
+ ),
270
+ ))
271
+
272
+ register(PromptTemplate(
273
+ name="audit:observability",
274
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: observability.md\n"
275
+ "Dimensions: 1.metric completeness 2.metric name accuracy "
276
+ "3.alert thresholds 4.logging config 5.health checks",
277
+ user_template=(
278
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
279
+ "Observability skeleton:\n{skeleton}\n\n"
280
+ "Audit observability.md against source code."
281
+ ),
282
+ ))
283
+
284
+ register(PromptTemplate(
285
+ name="audit:async",
286
+ system_template=_AUDIT_SYSTEM_COMMON + "\nTarget: async-and-events.md\n"
287
+ "Dimensions: 1.thread pool config 2.async method completeness "
288
+ "3.event pub/sub relationships 4.failure handling 5.event timing",
289
+ user_template=(
290
+ "Module: {module_name}\nCurrent document:\n{doc_content}\n\n"
291
+ "Async/Event skeleton:\n{skeleton}\n\n"
292
+ "Audit async-and-events.md against source code."
293
+ ),
294
+ ))
295
+
296
+ # ---------------------------------------------------------------------------
297
+ # Built-in templates: Sync (incremental update)
298
+ # ---------------------------------------------------------------------------
299
+
300
+ register(PromptTemplate(
301
+ name="sync:section-update",
302
+ system_template=(
303
+ "You are a knowledge base maintainer. Update a specific document section "
304
+ "based on source code changes.\nRules:\n"
305
+ "- Only rewrite the affected section, preserve the rest\n"
306
+ "- Maintain existing document structure and style\n"
307
+ "- Write from business perspective, not code translation\n"
308
+ "- Output the complete updated section content in Chinese\n"
309
+ "- Do NOT output anything outside the section content"
310
+ ),
311
+ user_template=(
312
+ "Document type: {doc_type}\nSection heading: {section_heading}\n\n"
313
+ "Current section content:\n{old_content}\n\n"
314
+ "Changed source files:\n{changed_files}\n\n"
315
+ "Skeleton delta:\n{skeleton_delta}\n\n"
316
+ "Rewrite this section to reflect the source code changes."
317
+ ),
318
+ ))
319
+
320
+ # ---------------------------------------------------------------------------
321
+ # Audit doc_type → template name mapping
322
+ # ---------------------------------------------------------------------------
323
+
324
+
325
+ def get_audit_doc_type_map(preset: dict | None = None) -> dict[str, str]:
326
+ """Generate audit template mapping from preset doc_types dynamically."""
327
+ if preset:
328
+ doc_types = preset.get("doc_types", {})
329
+ if doc_types:
330
+ result: dict[str, str] = {}
331
+ for dt_key in doc_types:
332
+ short = dt_key.split("-")[0] if "-" in dt_key else dt_key
333
+ result[dt_key] = f"audit:{short}"
334
+ return result
335
+ # Fallback for backward compat
336
+ return AUDIT_DOC_TYPE_MAP
337
+
338
+
339
+ AUDIT_DOC_TYPE_MAP: dict[str, str] = {
340
+ "source-tree-analysis": "audit:source-tree",
341
+ "data-models": "audit:data-models",
342
+ "api-contracts": "audit:api-contracts",
343
+ "architecture": "audit:architecture",
344
+ "business-logic": "audit:business-logic",
345
+ "messaging": "audit:messaging",
346
+ "caching": "audit:caching",
347
+ "enums-and-constants": "audit:enums",
348
+ "utils": "audit:utils",
349
+ "external-integrations": "audit:external",
350
+ "database-access": "audit:database",
351
+ "scheduled-tasks": "audit:scheduled",
352
+ "error-handling": "audit:error",
353
+ "security": "audit:security",
354
+ "aop-and-interceptors": "audit:aop",
355
+ "observability": "audit:observability",
356
+ "async-and-events": "audit:async",
357
+ }
@@ -0,0 +1,162 @@
1
+ """Template parity validation — ensures CLI and Agent templates stay in sync.
2
+
3
+ Validates that:
4
+ 1. Every CLI_Template (audit:*, sync:*) has a corresponding Agent_Template .md file
5
+ 2. Variable placeholders match between CLI and Agent versions
6
+ 3. No orphaned Agent templates without CLI registration
7
+
8
+ Usage:
9
+ python -m core.prompt validate-parity --preset java-spring
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import re
15
+ import sys
16
+ from dataclasses import dataclass
17
+ from pathlib import Path
18
+
19
+
20
+ @dataclass
21
+ class ParityViolation:
22
+ """A single parity violation."""
23
+
24
+ template_name: str
25
+ violation_type: str # "missing_agent", "missing_cli", "variable_mismatch"
26
+ detail: str
27
+
28
+
29
+ def validate_parity(preset_name: str) -> list[ParityViolation]:
30
+ """Compare CLI templates against Agent template files.
31
+
32
+ Returns list of violations (empty = all good).
33
+ """
34
+ from core.prompt.templates import _REGISTRY as REGISTRY
35
+ from core.preset import PRESETS_DIR
36
+
37
+ violations: list[ParityViolation] = []
38
+ templates_dir = PRESETS_DIR / preset_name / "templates"
39
+
40
+ if not templates_dir.is_dir():
41
+ violations.append(ParityViolation(
42
+ template_name="*",
43
+ violation_type="missing_agent",
44
+ detail=f"Templates directory not found: {templates_dir}",
45
+ ))
46
+ return violations
47
+
48
+ # Check CLI → Agent direction
49
+ for name, template in REGISTRY.items():
50
+ if not (name.startswith("audit:") or name.startswith("sync:")):
51
+ continue
52
+
53
+ # Expected agent template filename: "audit:business-logic" → "subagent-audit-business-logic.md"
54
+ agent_filename = "subagent-" + name.replace(":", "-") + ".md"
55
+ agent_path = templates_dir / agent_filename
56
+
57
+ if not agent_path.exists():
58
+ violations.append(ParityViolation(
59
+ template_name=name,
60
+ violation_type="missing_agent",
61
+ detail=f"Agent template not found: {agent_filename}",
62
+ ))
63
+ continue
64
+
65
+ # Compare variables
66
+ cli_vars = _extract_cli_variables(template)
67
+ agent_vars = _extract_agent_variables(agent_path)
68
+
69
+ missing_in_agent = cli_vars - agent_vars
70
+ missing_in_cli = agent_vars - cli_vars
71
+
72
+ if missing_in_agent:
73
+ violations.append(ParityViolation(
74
+ template_name=name,
75
+ violation_type="variable_mismatch",
76
+ detail=f"Variables in CLI but not Agent: {sorted(missing_in_agent)}",
77
+ ))
78
+ if missing_in_cli:
79
+ violations.append(ParityViolation(
80
+ template_name=name,
81
+ violation_type="variable_mismatch",
82
+ detail=f"Variables in Agent but not CLI: {sorted(missing_in_cli)}",
83
+ ))
84
+
85
+ # Check Agent → CLI direction (orphaned agent templates)
86
+ for md_file in sorted(templates_dir.glob("subagent-audit-*.md")):
87
+ # "subagent-audit-business.md" → "audit:business"
88
+ stem = md_file.stem # "subagent-audit-business"
89
+ parts = stem.split("-", 1) # ["subagent", "audit-business"]
90
+ if len(parts) < 2:
91
+ continue
92
+ cli_name = parts[1].replace("-", ":", 1) # "audit:business"
93
+ if cli_name not in REGISTRY:
94
+ # Not a violation if CLI templates haven't been registered yet
95
+ # (Agent templates can exist ahead of CLI registration)
96
+ pass
97
+
98
+ for md_file in sorted(templates_dir.glob("subagent-sync-*.md")):
99
+ stem = md_file.stem
100
+ parts = stem.split("-", 1)
101
+ if len(parts) < 2:
102
+ continue
103
+ cli_name = parts[1].replace("-", ":", 1)
104
+ if cli_name not in REGISTRY:
105
+ pass
106
+
107
+ return violations
108
+
109
+
110
+ def _extract_cli_variables(template) -> set[str]:
111
+ """Extract variable placeholders from a CLI PromptTemplate."""
112
+ variables: set[str] = set()
113
+ # PromptTemplate uses {variable_name} syntax
114
+ text = template.system + "\n" + template.user
115
+ for match in re.finditer(r'\{(\w+)\}', text):
116
+ variables.add(match.group(1))
117
+ return variables
118
+
119
+
120
+ def _extract_agent_variables(agent_path: Path) -> set[str]:
121
+ """Extract variable placeholders from an Agent template .md file."""
122
+ variables: set[str] = set()
123
+ try:
124
+ content = agent_path.read_text(encoding="utf-8")
125
+ except OSError:
126
+ return variables
127
+
128
+ # Agent templates use {variable_name} syntax
129
+ for match in re.finditer(r'\{(\w+)\}', content):
130
+ var = match.group(1)
131
+ # Filter out common false positives (JSON examples, etc.)
132
+ if var not in ("json", "else", "if", "endif", "status", "dimension", "detail", "fix"):
133
+ variables.add(var)
134
+
135
+ return variables
136
+
137
+
138
+ def main() -> None:
139
+ """CLI entry point for parity validation."""
140
+ import argparse
141
+
142
+ parser = argparse.ArgumentParser(
143
+ prog="python -m core.prompt validate-parity",
144
+ description="Validate CLI/Agent template parity",
145
+ )
146
+ parser.add_argument("--preset", required=True, help="Preset name")
147
+ args = parser.parse_args()
148
+
149
+ violations = validate_parity(args.preset)
150
+
151
+ if violations:
152
+ print(f"❌ {len(violations)} parity violation(s) found:\n")
153
+ for v in violations:
154
+ print(f" [{v.violation_type}] {v.template_name}: {v.detail}")
155
+ sys.exit(1)
156
+ else:
157
+ print(f"✅ All templates in sync for preset '{args.preset}'")
158
+ sys.exit(0)
159
+
160
+
161
+ if __name__ == "__main__":
162
+ main()